Java

[Java] Scanner, BufferedReader, BufferedWriter

HSRyuuu 2023. 6. 26. 22:41

Scanner와 BufferdReader의 차이

BufferedReader, BufferedWriter은 버퍼를 사용하여 읽기, 쓰기를 하는 함수이다.

버퍼를 사용하지 않는 입력은 키보드의 키를 누르는 즉시 프로그램에 전달된다.
버퍼를 사용하는 입력은 키보드의 입력 이 있을 때마다 한 문자씩 버퍼로 전송한다.
이 버퍼가 가득차거나 줄 바꿈을 하면 버퍼의 내용을 한 번에 프로그램에 전달한다.

 

Scanner은 1KB의 버퍼를 갖고, BufferedReader는 8KB의 버퍼를 가진다.
즉, Scanner은 더 자주 프로그램에 전달하고, BufferedReader은 조금 더 모아놨다가 프로그램에 전달한다.
( 쓰레기가 생길때마다 나가서 버리는 거랑, 쓰레기통에 모아놨다가 한 번에 버리는 차이 )

버퍼는 키보드와 프로그램 사이에 데이터 저장 공간 이라고 보면 될 것 같다.

 

또한, Scanner는 입력 시 내부에서 정규표현식, 입력값 분할, 파싱 과정 등을 상당히 많이 거치고 출력되기 때문에 속도가 느리다.


1. Scanner

1) 선언

Scanner sc = new Scanner(System.in);

2) 메서드

Scanner sc = new Scanner(System.in);
String str = sc.nextLine(); // 한줄 모두 입력받음
int i = sc.nextInt(); // 공백을 기준으로 하나의 int값을을 입력받음

3) 사용 예제

  • 값을 받을 때, Scanner는 공백을 기준으로 값을 구분한다.

(입력)

1 2
3

(code)

Scanner sc = new Scanner(System.in);

int a = sc.nextInt();
int b = sc.nextInt();
int c = sc.nextInt();

System.out.println(a+b+c);
//a:1 , b:2 , c:3 
// 6 출력

2. BufferedReader

1) 선언

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

2) 사용 방법

BufferedReader는 입력을 한줄씩 읽어 들인다.

readLine() 메서드를 통해 한 줄을 입력받을 수 있다.
입력받음과 동시에 다음줄로 넘어가서, 다시 한번 readLine()를 실행하면 그다음줄을 읽게 된다.


3) 예제 1

(입력)

abcd
efgh

(code)

String str1 = br.readLine();
String str2 = br.readLine();

(결과)
str1에는 "abcd"가, str2에는 "efgh"가 들어간다.


4) 예제 2

  • BufferedReader는 한 줄을 전부 입력받기 때문에 StringTokenizer와 함께 사용한다.
  • StringTokenizer를 사용하면 한 줄의 문자열에 담긴 내용을 어떤 기준(대부분 공백" ")으로 나눌 수 있다.

(입력)

hi !! 456
hello world !!

(code)

StringTokenizer st = new StringTokenizer(br.readLine);

String str = br.readLine();
String str1 = st.nextToken();
String str2 = st.nextToken();
int value = Integer.parseInt(st.nextToken());

(결과)
str : "hello world!!"
str1 : "hi"
str2 : "!!"
value : 456


5) 예제 3

조금 더 복잡한 예제이다.

첫째 줄에서 세로 N = 3 , 가로 M = 4 , 값 V = 99를 입력받고

2~4째 줄에서 int[N][M] board에 값을 입력받는 과정을 알아보자.

우선 첫째줄을 br.readLine으로 읽어와서 st에 넣어준다.

그렇게 되면 st에 3, 4, 99가 문자열 형태로 담기게 된다.

각각 st.nextToken()으로 N, M, V에 값을 할당해 준다.

 

그 아래부터는 한줄에 한 행씩 값이 들어온다.

따라서 한 주기가 끝날 때 마다 st = new StringTokenizer(br.readLine()); 으로 갱신해 준다.

 

안쪽 for문에서는 바깥쪽 for문 에서 새롭게 선언한 st를 이용해서 st.nextToken()으로 값을 가져오는 것을 반복한다.

BufferedReader br = new BufferedReader(new InputStreamReader((System.in)));

StringTokenizer st = new StringTokenizer(br.readLine());
int N = Integer.parseInt(st.nextToken()); //세로
int M = Integer.parseInt(st.nextToken()); //가로
int V = Integer.parseInt(st.nextToken()); 

int[][] ground = new int[N][M];

for(int i=0;i<N;i++){
    st = new StringTokenizer(br.readLine());
    
    for (int j = 0; j < M; j++) {
        ground[i][j] = Integer.parseInt(st.nextToken());
    }
}

3. BufferedWriter

1) 선언

BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

2) 사용 방법

write() 메서드를 이용하여 BufferedWriter에 입력받는다.
flush() 메소드를 이용해서 console에 직접 출력한다.

  • 한번 flush()로 출력하고, 다시 write()를 이용해 입력받고 다시 출력할 수 있다.

3) 단점

BufferedWriter는 비동기적 버퍼 스트림이다.
즉, 입력받은 데이터가 점점 채워지다가 버퍼가 꽉 차버리면 버퍼에 있는 데이터를 자동으로 비운다.

  • flush()는 곧 버퍼가 다 차지 않았지만, 출력을 하는 메서드이다.

StringBuilder와 유사하다. (그냥 StringBuilder 쓰자...)

 

StringBuilder
https://innovation123.tistory.com/17

4) 예제

        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        String str = "world!!";
        bw.write("hello"+" "+str+"\n");
        bw.flush();

        bw.write("hello~~");
        bw.write(str);
        bw.flush();

(출력)
hello world!!
hello~~ world!!

  • 중간에 flush()를 한번 실행하고, 다시 입력받아서 다시 실행했다.

 


 

Scanner, System.out.println을 이용한 게 더 간결해 보이지만,
데이터, 속도 측면에서 보면 BufferedReader, BufferedWriter을 사용하는 게 좋다.
입력을 많이 받아야 하는 경우, BufferedReader를 이용하는 것이 좋다.
알고리즘 문제를 풀 때는
BufferedReader , StringTokenizer, StringBuilder조합을 사용하는 것을 추천한다.


백준 11725번 그래프 문제이다. 

이 문제에서는 출력을 노드 개수 -1 개 만큼 하고, 최대 노드의 개수는 10만개 이다.

이 문제의 마지막에서는 문제를 풀며 값을 담았던 list의 값들을 한줄에 하나씩 출력한다.

아래(첫번째 제출)은 list를 순회하면서 System.out.println() 으로 출력했을 때이고,

위 (두번째 제출)은 StringBuilder를 선언 한 뒤 list를 순회하며 StringBuilder에 append 하고 마지막에 딱 한번 

System.out.println(stringBuilder); 로 출력한 결과이다.

 

이렇게 출력 방법 차이로 시간 차이가 많이 나게 된다.

 

만약 여기서 Scanner로 입력받고 첫번째 방법으로 출력한다면 시간은 더 오래 걸릴 것이다.

 

따라서 위에서 말했듯이 알고리즘 문제를 풀 때는
BufferedReader , StringTokenizer, StringBuilder조합을 사용하는 것을 추천한다.

반응형