CS 공부/자바 (Java)

[JAVA] BufferedReader 와 Bufferedwriter

Ju Young Pang 2022. 4. 10. 15:00

1. BufferedReader 와 Bufferedwriter이란?

BufferedReader와 BufferedWriter은 버퍼(Buffer)을 이용해 입출력을 하는 클래스이다.

BufferedReader는 Scanner과, BufferedWriter은 System.out.print();과 비슷한 동작을 하게 도와주는 클래스이며, Scanner과 System.out.println() 대신 이 들을 쓰는 것은 이들이 더 빠른 속도를 보이기 때문이다.

2. 버퍼(Buffer)란?

버퍼는 데이터 처리 속도가 다른 두 장치 사이에서 임시 저장 장치로써 역할을 한다.

예를들어, 컨베이어 벨트로 1분에 하나씩 도착하는 짐을 10초 거리에 있는 트럭으로 옮겨야하는 상황이라고하자. 짐이 하나씩 도착을 할 때마다 트럭으로 여러번 옮기는 것보다는 짐이 도착하면 우선 수레에 쌓아두고, 수레가 다 차면 한번에 트럭으로 옮기는 것이 더 효율적일 것이다.

여기서 컨베이어벨트는 하드디스크를, 버퍼는 수레를, 그리고 트럭으로 짐을 옮기는 사람은 CPU를 뜻한다.

한마디로 버퍼는 속도가 느린 하드디스크로 인해 속도가 빠른 CPU가 일을 쉬는 것을 방지하는 역할을 하는 것이다.

3-1. BufferedReader

BufferedReader은 Scanner과 다르게 모든 공백(엔터, 스페이스)을 경계로 입출력을 받아오는 것이 아닌, 개행만을 경계로 사용한다. 따라서 다른 구분자들을 사용하기 위해서는 StringTokenizer 클래스를 사용한다.

또한, nextInt()등을 이용해 다양한 데이터 타입으로 입력을 받을 수 있는 Scanner과 달리 오직 readLine()만을 이용해 오직 String 데이터 타입만을 받을 수 있어서 형변환(e.g. Integer.parseInt())을 해줘야한다.

3-2. BufferedWriter

글을 자세히 읽었다면 알고있겠지만 BufferedWriter은 System.out.println()이 아닌 System.out.print()와 유사하다. 따라서 개행이 뒤에 자동으로 추가되지 않는다. 개행을 위해는 write() 함수 안에 "\n"을 추가해주거나 newLine() 함수를 사용한다.

버퍼를 다 사용한 이후에는 flush()를 이용해 버퍼를 리셋해준 다음 close()를 이용해 스트림을 닫아주어야한다.

4. 함께 사용하면 좋은 클래스들

4-1. StringTokenizer

구분자를 기준으로 토큰을 생성한다.

initializer에는 3가지의 parameter이 들어갈 수 있다.

StringTokenizer(*String 토큰화할라인, String 구분자(default:" "), boolean 구분자포함여부(default:false))

String str1 = "안녕 만나서 반가워";
StringTokenizer tok = new StringTokenizer(str1);
while(tok.hasMoreTokens()) {
	System.out.println(tok.nextToken());
}

System.out.println();
        
String str2 = "아침,점심,저녁";
tok = new StringTokenizer(str2,",");
while(tok.hasMoreTokens()) {
	System.out.println(tok.nextToken());
}

System.out.println();

tok = new StringTokenizer(str2,",",true);
while(tok.hasMoreTokens()) {
	System.out.println(tok.nextToken());
}
#output
안녕
만나서
반가워

아침
점심
저녁

아침
,
점심
,
저녁

4-2. StringBuilder

String은 변경이 불가능하기 때문에 문자열을 concatenate(+)하게 되면 새로운 문자열을 만들게된다. 따라서 메모리 효율을 위해 가변적인 StringBuilder을 사용할 수 있다.

5. 코드 사용 예

import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.BufferedWriter;
import java.io.OutputStreamWriter;
import java.util.StringTokenizer;

public class Main {
    //throws IOException 필수
    public static void main(String[] args) throws IOException{
        //BufferedReader
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); //선언
        String s = br.readLine(); //String 읽어오기
        int i = Integer.parseInt(br.readLine()); //int 읽어오기

        //StringTokenizer 공백 단위로 String 쪼개기
        //단어(공백)숫자 형태로 되어있는 경우 (예: 주영 102)
        StringTokenizer tkn  = new StringTokenizer(br.readLine());
        String a = tkn.nextToken();
        int b = Integer.parseInt(tkn.nextToken());

        //=====================================================
        
        //String Builder
        StringBuilder sb = new StringBuilder();
        sb.append("Read from BufferedReader: ").append(s).append(" ").append(i).append("\n");
        sb.append("Read from StringTokenizer: ").append(a).append(" ").append(b).append("\n");
        
        //BufferedWriter
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));   //선언
        bw.write(sb.toString());   //출력
        bw.newLine(); //개행 역할
        bw.flush();   //남아있는 데이터를 모두 출력시킴
        bw.close();   //스트림을 닫음
    }
}
#input
hi
123
bye 321
#output
Read from BufferedReader: hi 123
Read from StringTokenizer: bye 321