언어 공부/JAVA_자바

[JAVA / 자바] Scanner와 BufferedReader / System.out.print와 BufferWriter의 차이

Seunghyun_KO 2021. 12. 12. 09:00
728x90
반응형

여러분들은 Scanner함수와 System.out.print함수를 아마도 즐겨 쓰고 있을 것입니다. 왜냐면 입출력 시에 이 두 함수가 사용하기도 편리하고 쉽기 때문이죠, 하지만 나중에 시간 초과에 걸릴 위험이 큰 함수들이 바로 Scanner와 System.out.print함수입니다.

 

그렇다면 시간 초과에 걸리지 않을 방법은 무엇일까요?

바로, BufferReader함수와 BufferWriter함수가 해법이 될 수 있습니다. 왜 그럴까요?

 

Scanner

1. 입력을 받으면 이것이 어떠한 형의 단어인지 구분하여 분석을 한다.(int, String 등,,,)

2. 입력값의 경계로 공백, 엔터 모두 인식이 가능하다.

3. 사용하는 버퍼의 사이즈는 1024 chars이다.

4. 문자열 파싱이 가능하다.

5. IOException을 숨긴다.

6. 동기화되지 않는다.

 

BufferedReader

1. String의 형태로만 입력을 받는다.(다른 형으로 사용하려면 형 변환이 필요함.)

2. 입력값의 경계로 엔터만 인식이 가능하다.

3. 사용하는 버터의 사이즈는 8192 chars이다.

4. 문자열 파싱이 불가능하다.

5. IOException을 던진다.

6. 입력 시 바로 동기화가 된다.

7. 입력된 데이터가 바로 프로그램으로 전달되는 것이 아니라 버퍼를 통해 한번에 전달된다.★

 

위 특징들을 종합해보면

편의성 : Scanner > BufferedReader

효율성 : Scanner < BufferedReader

라고 볼 수 있다.

 

Scanner함수는 정말 편리하게 사용이 가능하지만 BufferReader함수는 프로그래밍 시 많은 코드를 요한다.

BufferReader함수와 BufferWriter함수를 사용하는 예시를 아래의 코드에 주석 와 함께 달아놓았으니 참고 바란다.

사용 예시

- Scanner / System.out.println

import java.util.Scanner;

public class Main {
    public static void main(String args[]) {
    Scanner input = new Scanner(System.in);
    int num = input.nextInt();
    String str = input.next();
    string line = input.nextLine();
    
    System.out.println(num);
    System.out.println(str);
    }
}

- BufferedReader / BufferedWriter

import java.io.IOException;

import java.io.BufferReader; //BufferedReader패키지
import java.io.InputStreamReader;

import java.io.BufferedWriter; //BufferWriter패키지
import java.io.OutputStreamWriter;

import java.util.StringTokenizer; //공백문자도 구분할 수 있도록 도와주는 패키지

public class Main {
    public static void main(String args[]) throws IOException { //IOException 던짐
        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
       	String str = bf.readLine(); //일반 입력
    	int num = Integer.parseInt(bf.readLine()); //int로 형 변환 입력
        
        /**
        공백 문자도 입력의 경계로 받아들이려면 다음과 같은 코드로 작성해주면 된다.
        StringTokenizer st = new STringTokenizer(bf.readLine());
        String str = st.nextToken();
        int num = Integer.parseInt(st.nextToken()); //마찬가지로 형 변환 필요
        */
        
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        bw.write(str); //일반 출력
        bw.flush(); //버퍼에 남아있는 모든 데이터 출력(꼭 있어야 하는 코드는 아님.)
        bw.close(); //스트림 닫아주기
    }
}

(* BufferedWriter의 출력에서 숫자형은 출력이 되지 않는다. 따라서 숫자를 출력할 때는 String.ofValue() 함수를 사용하여 문자열로 형 변환 후 출력하거나, (정수+"") 이런 식으로 출력에 문자열이 추가되면 정상적으로 출력이 된다.)

 

마찬가지로 입력도 출력과 동일하다.

어느 정도의 성능 차이를 보이냐면 총 N개의 줄에 1부터 10,000,000까지의 자연수를 한 줄에 하나씩 출력하는 시간을 측정한 결과는 다음과 같다.

출력 방법 평균 (초)
BufferedWriter bf  bf.write(i + "\n"); 0.9581
System.out.println(i); 30.013

출처: https://www.acmicpc.net/blog/view/57#comments

대략 30배의 차이가 난다.

 

이 차이는 입출력하는 양에 따라 더욱 격차가 벌어진다. 따라서 입출력 양이 많을 때는 BufferedReader, BufferedWriter함수를 사용하고 그 외의 경우에는 Scanner, System.out.println함수를 이용하여 편의성을 추구해도 좋을 것 같다.


EOF(End Of File) 처리

 - Scanner

변수.hasNext(); // 문자열 입력이 다음에 있는가?
변수.hasNextInt(); // 정수형 입력이 다음에 있는가?

 - BufferedReader

(문자열_변수 = 변수.readLine()) != null // 줄 입력을 받을 때 입력이 없으면 null을 반환하는 성질을 이용

Scanner 함수의 경우 다음 입력의 유무를 판단할 수 있는 내장 함수가 있지만,

BufferedReader함수의 경우 다음 입력의 유무를 판단할 수 있는 내장 함수가 없다.

따라서 BufferedReader함수를 사용할 때 입력의 끝을 판단할 수 있는 방법은 다음 입력이 없으면 null을 반환하는 성질을 이용하여 입력이 null인지 아닌지 판단하면 된다.

728x90
반응형