[JAVA] Buffer input/output
Stream
stream : byte 형태로 데이터를 운반하는데 사용되는연결 통로.
물이 한쪽 방향으로만 흐르는 것과 같이 스트림은 단방향 통신만 가능하기 때문에 하나의 스트림으로 입력과 출력을 동시에 처리 할 수 없다. 스트림은 먼저 보낸 데이터를 먼저 받게 되어있으며 연속적으로 데이터를 주고 받는다는 점에서 큐(queue)의 FIFO(First in Frist Out) 구조로 되어 있다.
Stream 활용 : InputStream / OutputStream
입력 스트림 inputStream 은 스트림을 한 줄 씩 읽고, 출력스트림 outputStream 으로 데이터를 내보내며 해당 공간을 비운다. InputStream 은 System.in을 사용하며, OutputStream 은 System.out 을 사용.
출력을 위해서는 out.write() 후 flush() 와 close() 를 모두 사용해주어야한다.
- flush 는 write 에 저장된 값을 출력함과 동시에 비워주는 역할.
- close() 는 끝 마무리해주는 역할.
InputStream / OutputStream는 단 하나의 값밖에 입력받지 못하고, 출력 또한 하나의 값만 입력 받는다.
여러 값을 출력 받기 위한 방법 : InputStreamReader/OutputStreamWriter
다만, InputStreamReader에서 2개 이상의 값을 받아오기 위해서는 배열을 사용해서 값을 받아와야 한다.
⇒ 효율이 나쁘다.
Buffer
- Buffer(이하 버퍼)는 위의 InputStream 과 InputStreamReader 를 보완하고 합쳐서 탄생한 입출력의 최종형태.
- 버퍼는 고정값이 아니라 가변적인 값을 받게 된다.
- 버퍼는 입력받은 값은 버퍼에 저장해두었다가 버퍼가 가득차거나 개행 문자가 나타나면 버퍼의 내용을 한 번에 전송하게 된다.
import java.io.BufferedReader; // 임포트 필수
import java.io.BufferedWriter;
public static void main(String[] args) throws IOException { // 여기도 필수! 아니면 try ~ catch 사용해야함
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));
}
Buffer 사용법
1) BufferedReader
import java.io.BufferedReader; // 임포트 필수
import java.io.BufferedWriter;
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();
// bufferedReader 의 기본형은 String / 한줄단위로 읽는다.
int i = Integer.parseInt(s);
// String 을 int로 형변환
br.close(); // bufferedreader 도 입력을 마쳤다면 닫아주자. 필수는 아님.
}
Buffer 의 기본 타입은 String 이며, 엔터(enter)를 경계로 값을 인식한다.
이 때문에 중간에 띄어쓰기(스페이스) 를 기준으로 값을 분리해야하는 경우 따로 데이터를 가공해주어야 한다.
2) Stringtokenizer & split
StringTokenizer st = new StringTokenizer(br.readLine());
// 한줄씩 읽고 공백단위로 끊어준다.
// 줄 읽을때마다 새로 변수 생성해야한다.
// ex) arr[j] = Integer.parseInt(st.nextToken());
// 공백단위로 끊은 문자열을 정수로 변환해서 각각 배열에 넣어준다.
// 위와 같이 공백으로 받을경우 나눠서 담을 수도 있고,
//.split 사용해서 담는 것도 가능. 하지만 stringtokenizer가 더 효율적.
String[] s = br.readLine().split(" ");
// Integer.parseInt(s[0])
문자열을 자르게 위해 split을 사용할땐, split은 정규식을 기반으로 자르는 로직으로서 내부는 복잡하다.
그에 비해 StringTokenizer의 nextToken()메소드는 단순히 공백 자리를 땡겨 채우는 것이다.
그렇기 때문에 소도 차이가 날 수 밖에 없다.
정규식이나 인덱스 접근과 같은 처리가 필요없다면 StringTokenizer를 사용하는 것이 효율적이다.
3) Stringtokenizer 응용
BufferedReader br = new BufferedReader(new InputStreamReader(System.in);
StringTokenizer st = new StringTokenizer(br.readLine());
// AB CDD EFFF GH 입력
st.nextToken() // AB
st.nextToken() // CDD
st.nextToken() // EFFF
st.nextToken() // GH
String str = "this%%is%%my%%string";
StringTokenizer st = new StringTokenizer(str,"%%");
while(st.hasMoreTokens()) {
System.out.println(st.nextToken());
}
// this is my string
4) bufferedwriter
bw.write("입력받은 값 : "+ s); // 출력
bw.newLine(); // 개행 메소드
bw.write("입력받은 값 : "+i+"\n"); // 이렇게 하니까 제대로 출력됨
bw.flush(); // 남은 값 출력 && 버퍼 초기화
bw.close(); // bufferedwriter 닫기
bufferedwriter도 기본적으로 string 형태로 출력한다.
따라서 정수형만을 출력하려고 하면 주소값을 출력하게 된다.
br이 integer.parseint 해준 것처럼 bw도 정수값을 출력하려면 변화시켜주어야 한다.
for(int i=0; i<onelist.size(); i++) {
bw.write(String.valueOf(onelist.get(i)));
// 정수값 변환하여 출력
bw.newLine(); //개행
}
bw.write(String.valueOf(sum));
br.close();
bw.flush();
bw.close();