Java 입출력
자바에서는 모든 I/O가 Stream(스트림)을 통해 이루어진다.
Stream
스트림은 Byte형태로 테이터를 운반하는 데 사용되는 연결통로라고 생각하면 된다. 이는 자료(data)의 흐름이 물의 흐름과 같다는 의미에서 사용되었다고 한다.
다만 물이 한쪽 방향으로만 흐르는 것과 같이 스트림은 단방향 통신만 가능하기 때문에 하나의 스트림으로 입력과 출력을 동시에 처리할 수 없다.
또한 스트림은 먼저 보낸 데이터를 먼저 받게 되어있으며 연속적으로 데이터를 주고 받는다는 점에서 큐(queue)의 FIFO(First in First Out) 구조로 되어있다.
이때 데이터의 스트림의 근원지(시작점)을 Source, 데이터 종착점을 Sink, 연결한 것을 Stream이라고 표현
하며, Source 입력 스트림 ▶ Input Stream ▶ 출력 스트림 Output Stream ▶ Sink로 연결된다.
요약하자면 스트림(Stream)은 Byte 형태로 데이터를 운반하는 데 사용되는 연결통로로써 단방향 통신을 하며, 큐의 FIFO 구조로 되어있다.
또한 입력과 출력을 동시에 수행하려면 입력을 위한 입력 스트림(Input Stream)과 출력을 위한(Output Stream) 모두 2개의 스트림이 필요하다는 것이다.
Stream 활용 : InputStream / OutputStream
자바에서는 처리 단위에 따라 Reader - InputStream / Writer - OutputStream으로 나뉘어 통신한다. 이 때 입력 스트림 InputStream은 스트림을 한 줄씩 읽고, 출력 스트림 OutputStream으로 데이터를 내보내며 해당 공간을 비운다.
즉, 컴퓨터와 키보드를 연결하여 '입력' 받는 것은 입력 스트림인 InputStream의 역할이며, 컴퓨터에 입력된 정보를 모니터로 출력하는 것은 출력 스트림 OutputStream의 역할이라고 할 수 있다.
이 때 InputStream은 System,in 을 사용하며, OutputStream은 System.out을 사용한다.
InputStream / OutputStream운 자바에서 다음과 같이 사용할 수 있다.
package com.board.study.entity.board;
import java.io.InputStream;
import java.io.OutputStream;
/*
* InputStream 으로 입력받는 경우 맨 앞 문자 1개만 출력됨 && int 형태로 입력받음
* */
public class qq() {
public static void main(String[] args) throws IOException {
InputStream in = System.in;
OutputStream out = System.out;
int idata = in.read(); // input 은 read 와 연결되어있기 때문에 in.read 를 사용한다.
out.write(idata); // output 은 write 와 연결되어있기 때문에 out.write 를 사용한다.
out.flush(); // flush 를 써주지 않으면 출력되지 않는다.
out.close(); // output 을 끝내는 메서드
}
}
이 때 중요한 것은 다음과 같다.
● InputStream으로 받아오는 경우 여려 개의 값을 입력해도 단 1개의 문자밖에 못 가져오며 기본형은 int로 받아온다.
따라서 char 형태로 표현하고 싶다면, char 타입으로 캐스팅 해주어야 한다.
● 출력을 위해서는 out.write() 후 flush() 와 close() 를 모두 사용해 주어야한다. flush() 는 write 에 저장된 값을 출력함과 동시에 비워주는 역할이고, close() 를 끝 마무리 해주는 역할이다.
InputStreamReader / OutputStreamWriter
InputStream / OutputStream 은 단 하나의 값밖에 입력받지 못하고, 따라서 출력도 하나밖에 못한다.
그래서 해결책으로 InputStreamReader / OutpurStreamWriter이다.
package com.board.study.entity.board;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
/*
* InputStreamReader 로 입력받는 경우 배열을 어떻게 주느냐에 따라 2개 이상의 값을 받을 수 있음
* */
public class qq {
public static void main(String[] args) {
InputStream in = System.in;
InputStreamReader reader = new InputStreamReader(in); // InputStreamReader 사용하기 위해 객체 생성
OutputStream out = System.out;
OutputStreamWriter writer = new OutputStreamWriter(out); // OutputStreamReader 사용하기 위해 객체 생성
char cdata[] = new char[2]; // 이제는 char 를 기본적으로 받을 수 있고, 2개 이상의 값을 배열을 통해 받아올 수 있다.
reader.read(cdata);
int IcData = cdata[0] - '0'; // 배열이기 때문에 char 로 받은 값을 int 로 변환하여 계산하고 싶은 경우 이처럼 사용한다.
writer.write("입력받은 값 : ");
writer.write(cdata);
writer.write("\n");
writer.write("입력받은 첫번째 값 + 10 : ");
writer.write(IcData +10+"\n"); // 입력받은 첫번째 값 + 10
System.out.println("결과");
writer.flush(); // 이 메서드를 통해 출력
writer.close();
}
}
● InputStreamReader 를 통해서 2개 이상의 값을 받아오기 위해서는 배열을 사용해서 값을 받아와야 한다.
즉, InputStreamReader 는 고정적인 값 밖에 받아올 수 없다. 고정적인 값만 받아온다는 것은 내가 입력하는 값이 고정되어있는 값보다 적다면 그만큼 공간의 낭비가 생기게 되고, 고정 되어있는 값보다 크다면 공간이 부족해지는 문제가 발생한다. 효율이 나쁘다.
● char 타입을 기본형으로 하기 때문에 따로 캐스팅 할 필요는 없다. 다만 값을 int 로 변형하여 계산을 돌리고 싶은 경우는 위 코드 처럼 바꿔 주어야한다.
● 마지막에 writer.write() 로 여러번 써준 것은 결국 저렇게 써놓아도 flush() 에 가서 한번에 출력된다.
Buffer
버퍼는 위의 InputStream 과 InputStreamReader 를 보완하고 합쳐서 탕생한 입출력의 최종형태이다.
먼저 버퍼는 고정 값이 아니라 가변적인 값을 받게 된다. 즉 5개의 값을 받으면 5개의 공간이 사용되며, 10개의 값을 박으면 10개의 공간이 사용되어 보다 효율적이다.
동시에 버퍼는 입력받은 값은 버퍼에 저장해두었다가 버퍼가 가득차거나 개행 문자가 나타나면 버퍼의 내용을 한 번에 전송하게 된다.
결국 이러한 방식을 취하는 것은 양이 많을 경우 하나하나 옮기는 것보다 한 번에 옮기는 것이 빠르다.
단점
1. 코드가 복잡하다.
2. 띄어쓰기, 엔터 등 개행문자를 경계로 입력 값을 인식하는 Scanner 와 달리 BufferReader 는 엔터만 경계로 인식하기 때문에 중간에 띄어쓰기라도 하는 경우 데이터를 가공해주어야 한다.
3. Buffer 로 입력받는 기본 타입은 String 이기 때문에 int 로 계산해야 하는 경우에 형변화 해야한다.
Buffer 사용법
● Buffer 객체 생성 시에는 InputStream 과 InputStreamReader 의 합쳐진 형태를 취한다.
● Buffer 사용 시에는 java.io.Buffered 패키지 임포트 뿐만 아니라 throws IOException 을 사용하거나 try ~ catch 문을 넣어 주어야 한다.
import java.io.*;
public class ww {
public static void main(String[] args) throws IOException {
InputStream in = System.in;
InputStreamReader reader = new InputStreamReader(in);
OutputStream out = System.out;
OutputStreamWriter writer = new OutputStreamWriter(out);
// 위의 4줄이 아래의 하나의 줄로 줄어든다.
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
}
import java.io.*;
public class ww {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
String s = br.readLine(); // BufferedWriter 의 기본형은 String
int i = Integer.parseInt(s) + 10; // String 을 int 로 형변환 후 + 10
br.close(); // bufferedReader 도 입력 끝나면 닫아준다.
bw.write("입력받은 값 : " + s); // 출력
bw.newLine(); // 개행 메서드
bw.write("입력받은 값 + 10 : " + i + "\n");
bw.flush(); // 남은 값 출력 && 버퍼 초기화
bw.close(); // bufferedWriter 닫기
}
}
C:\jdk-11\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2021.3.2\lib\idea_rt.jar=53839:C:\Program Files\JetBrains\IntelliJ IDEA 2021.3.2\bin" -Dfile.encoding=UTF-8 -classpath C:\untitled\out\production\classes ww
65
입력받은 값 : 65
입력받은 값 + 10 : 75
정리
1. throws IOException {} 나 try ~ catch 문을 넣어주어야 한다.
2. Buffer 의 기본 타입은 String 이며, 엔터를 경계로 값을 인식한다. 이 때문에 중간에 띄어쓰기를 기준으로 값을 분리 해야 하는 경우 따로 데이터를 가공해주어야 한다.
3. BufferedWriter 을 사용해서 입력되었던 것들을 출력한다. 이후 flush() 를 사용하게 된다. 버퍼가 꽉 차기 전에는 출력되지 않는데 flush() 를 통해 꽉 차지 않아도 buffer 내용을 강제적으로 출력 후 버퍼를 비우게 된다.
'JAVA > Chapter14' 카테고리의 다른 글
Java - 람다식에서 메서드 참조/생성자 참조 사용법 (0) | 2022.09.01 |
---|---|
Java - ::(더블콜론) (0) | 2022.08.30 |
OutputStream 정의 (0) | 2022.08.25 |
InputStream 정의 (0) | 2022.08.25 |
입출력 스트림 (InputStream, OutputStream)란? (0) | 2022.08.24 |