Programming Languages/Java

[JAVA] BufferedReader, BufferedWriter 사용해야 하는 이유

Hannana. 2024. 6. 20. 10:26
반응형

자바에서 입력은 Scanner 통해 받고,

출력은 System.out.println("") 을 통해 한다.

 

평상시에는 이러한 입,출력이 문제가 되지 않지만 

특정 상황의 경우 이것을 쓰는 것이 적합하지 않을 때가 있다.

 

바로 코딩테스트와 같은 시간 제한이 주어진 상황에서 컴파일이 완료되어야 하는 경우이다.

원래 쓰던 대로 하면 시간 초과 오류가 뜬다.

이 때 오류를 해결할 수 있는 방법은 입, 출력을 더 빠르게 받는 것이다!

나는 코딩 테스트로 인해 이 방법을 알아보면서

StringBuffer가 성능이 좋은 이유가 있듯이, BufferReader가 더 빠른 이유가 궁금해졌다.

 


■ 버퍼링 개념
버퍼링은 데이터를 한 번에 조금씩 읽거나 쓰는 대신, 더 큰 덩어리로 읽거나 쓰는 방법이다. 이렇게 하면 디스크나 네트워크 같은 입출력 장치와의 상호작용 횟수를 줄여서 성능을 높일 수 있다.

■ BufferedReader

  • 기본 원리: BufferedReader는 문자 입력 스트림을 버퍼에 저장해 두었다가 필요할 때 한 번에 더 많은 양의 문자를 읽는다. 이를 통해 파일이나 네트워크로부터 데이터를 자주 읽는 것을 방지할 수 있다.
  • 동작 방식:
    1. 데이터를 읽을 때, BufferedReader는 내부 버퍼에 데이터를 한 번에 많이 읽어 둔다.
    2. 이후 프로그램에서 read() 메서드를 호출하면, 버퍼에 저장된 데이터에서 읽어오기 때문에 더 빠른 응답을 제공
    3. 버퍼가 비게 되면, 다시 한 번에 많은 데이터를 읽어서 버퍼를 채움

 BufferedWriter

  • 기본 원리: BufferedWriter는 문자 출력 스트림에 버퍼를 사용하여, 데이터를 한 번에 모아서 쓴 다음에 실제로 출력 장치에 쓰는 방식으로 동작
  • 동작 방식:
    1. 데이터를 쓸 때, BufferedWriter는 내부 버퍼에 데이터를 모아 둔다.
    2. 버퍼가 가득 차거나 명시적으로 flush() 메서드를 호출하면, 버퍼의 모든 내용을 한 번에 출력 장치로 보냄
    3. 이를 통해 출력 장치에 데이터를 자주 쓰는 것을 방지

 

왜 더 빠를까?

더 빠른 이유

  • 시스템 콜 감소: 입출력 작업은 시스템 콜(system call)을 필요로 하는데, 이 시스템 콜은 상당한 오버헤드를 유발. 버퍼링을 사용하면 시스템 콜의 "빈도"를 줄일 수 있다.
  • 효율적인 데이터 처리: 한 번에 많은 데이터를 읽거나 쓰기 때문에, 디스크나 네트워크 장치의 물리적인 접근 횟수를 줄여서 더 효율적인 데이터 처리가 가능
  • 메모리 사용 최적화: 메모리에 데이터를 임시로 저장해두고 처리하기 때문에, 매번 직접 입출력 장치와 상호작용하는 것보다 더 빠르게 데이터에 접근할 수 있다.

 

 

■ 사용 예시

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

public class Solution {

	public static void main(String[] args) throws IOException{
		// BufferedReader를 사용하기 위해 throws IOException 추가
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		
		
		int n = Integer.parseInt(br.readLine());
		int[] array = new int[n];
		
		StringTokenizer st = new StringTokenizer(br.readLine()); 
		for(int i=0; i<n; i++) {	// n만큼 배열에 토큰화하여 받기
			array[i] = Integer.parseInt(st.nextToken());
		}
		
		bw.write("ing -> String \n");
		for(int i=0; i<n; i++) {
			bw.write(String.valueOf(array[i]));
			bw.write(" ");
		}
		
		bw.flush();
		bw.close();
	}
}

 

-StringTokenizer를 이용해 입력 값 쪼개어 받기

-BufferedWriter 사용 시, 정수값을 넣을 때 String형으로 변환이 필요하다.

- write()메소드를 통해 출력할 내용을 담고, flush()를 통해서 버퍼를 비워내는 동시에 콘솔에 출력

-write() = 버퍼에 담는 과정

-콘솔에 출력하기 위해서는 반드시 flush()를 호출

-출력이 끝났으면. close()를 통해서 스트림 닫아주기

 

 

 

 

 

 

 

 

 

 

 

반응형