[Java] 빠른 입력과 출력: BufferedReader와 BufferedWriter + Buffer (with 백준15552)

소영·2025년 1월 4일
post-thumbnail

시작

백준 이 문제로부터 영감을 얻게 된 포스팅이다.

https://www.acmicpc.net/problem/15552
본격적으로 for문 문제를 풀기 전에 주의해야 할 점이 있다. 입출력 방식이 느리면 여러 줄을 입력받거나 출력할 때 시간초과가 날 수 있다는 점이다.
Java를 사용하고 있다면, Scanner와 System.out.println 대신 BufferedReader와 BufferedWriter를 사용할 수 있다. BufferedWriter.flush는 맨 마지막에 한 번만 하면 된다.

Buffer를 써본 적 없는 건 아니지만 확실히 기존에는 대부분 System.out.print와 Scanner로 처리하려고 했다. 정리해보면 좋을 것 같다.

Buffer?

일단, System.in과 System.out.print보다 BufferedReader, BufferedWriter를 쓰는 게 효율적이라고 한다.
버퍼가 뭐길래 효율적일까?

Buffer

버퍼란 데이터를 임시로 저장하는 메모리 공간이다. 버퍼를 사용하면 데이터 입출력 작업을 여러 번 요청하는 대신 한 번에 대량의 데이터를 처리할 수 있다.

BufferedReader

참고: Oracle 공식 문서

Read 요청을 기준으로 조금 더 자세히 들어가보자.

파일 속 내용과 같은 대량의 데이터를 한 번에 읽고, 이를 버퍼에 저장하여 사용자가 요청할 때마다 제공하면 디스크 접근 횟수가 줄어들기 때문에 Scanner보다 효율적이라고 할 수 있는 것이다.

Scanner에 버퍼가 없는 것은 아니지만 버퍼 크기가 BufferedReader보다 작고, nextInt()와 같이 형 변환 기능을 제공하는 경우가 있어, 단순히 텍스트 데이터를 읽기만 하고 변환하지 않는 BufferedReader보다는 느리다.

그러나 읽어야 하는 데이터가 적은 경우, 사용자가 콘솔에 입력하거나 데이터를 int형 등 다른 형으로 변환해야 하는 경우에는 BufferedReader보다 Scanner가 유용할 수 있다.


공식 문서에 따르면 일단 다음 패키지를 import 해야 한다. 하지만 어차피 이것 저것 추가하게 될테니 *로 하는 것이 낫겠다.

import java.io.BufferedReader;
///
import java.io.*;

콘솔 입력을 입력받는 경우 System.in을 이용한다. 이때는 java.io.InputStreamReader 패키지가 필요하다.

  • BufferedReader(): 버퍼를 입력해 입력
  • InputStreamReader(System.in): 사용자 입력 스트림
  • FileReader({filename}): 파일 입력 스트림

  • readLine(): 버퍼에서 한 줄씩 읽기
  • read(): 버퍼에서 한 글자씩 읽기
//선언
BufferedReader br =  new BufferedReader(new InputStreamReader(System.in));	
// 버퍼에서 한 줄씩 읽기
String str = br.readLine();

IOException을 고려한 예외처리까지 하면 다음과 같은 코드를 쓸 수 있다. 실제 실행 시에는 반드시 예외처리를 해야 한다.

import java.io.*;

public class Main {
    public static void main(String[] args) {
        try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

파일 데이터를 읽어보자. java.io.FileReader 패키지가 필요하다.

import java.io.*;

public class BufferedReaderExample {
    public static void main(String[] args) {
        try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

읽을 때 무조건 문자열 String으로 읽기 때문에 다른 형으로 변환하고 싶다면 형변환을 이용해야 한다. 예를 들어 정수형으로 바꾸고자 한다면 다음과 같이 할 수 있을 것이다.

int a = Integer.parseInt(br.readLine());

BufferedWriter

참고: Oracle 공식 문서

버퍼를 사용해 데이터를 모았다가 한 번에 출력한다. I/O 작업이 System.out.print보다 최소화되었으므로 빠르다.

마찬가지로 import한다.

  • BufferedWriter(): 버퍼를 이용해 출력
  • OutputStreamWriter(System.out): 콘솔 출력 스트림
  • FileWriter({filename}): 파일 출력 스트림

  • write(): 버퍼에 쓰기
  • newLine(): 버퍼에서 줄 바꾸기. write 시 "\n"을 함께 써도 된다.
  • flash(): 버퍼에 있는 내용을 모두 출력하기
  • close(): BufferedWriter를 종료하기
import java.io.*;

public class Main {
	public static void main(String[] args) {
    	try (BufferedWriter bw = new BufferedWriter(new FileWriter("output.txt"))) {
            for (int i = 1; i <= 1000; i++) {
                bw.write("This is line " + i);
                bw.newLine(); // 줄바꿈
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

백준 문제 해결

그렇다면 맨 위에서 언급한 '빠른 A+B' 문제는 아래 코드로 풀 수 있다.

import java.io.*;

public class Main{
    public static void main(String[] args){
        try{
            // BufferedReader, Writer 선언
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

            // 테스트 케이스의 개수 입력
            int t = Integer.parseInt(br.readLine());

            // 모든 테스트케이스에 대하여 반복
            for(int i = 0; i < t; i++){
                String str=br.readLine();
                // 띄어쓰기를 기준으로 A와 B 분리
                int idx = str.indexOf(' ');
                int a = Integer.parseInt(str.substring(0,idx));
                int b = Integer.parseInt(str.substring(1+idx,str.length()));
                // 연산과 저장
                bw.write((a+b)+""); // int를 문자열로 바꾸어 저장
                bw.newLine();
            }
            
            // 한 번에 출력
            bw.flush();
            bw.close();
            
        } catch(IOException e){
            e.printStackTrace();
        }

    }
}
profile
Hello World ✨

0개의 댓글