Java에서 데이터를 입출력할 때는 바이트 스트림과 문자 스트림이 사용됩니다. 바이트 스트림은 InputStream과 OutputStream의 하위 클래스들이며, 바이트 단위의 데이터를 처리합니다. 반면 문자 스트림은 Reader와 Writer의 하위 클래스들이며, 문자 단위로 데이터를 처리합니다. 하지만 이들 스트림을 그대로 사용해 한 바이트씩 또는 한 문자씩 입출력하는 방식은 비효율적입니다. 이를 개선하기 위해 버퍼 스트림이 도입되었습니다.
버퍼 스트림의 필요성
기본 스트림이 데이터를 한 바이트 또는 한 문자씩 읽고 쓰는 방식은 자주 운영체제와 통신을 하게 되어 많은 시스템 호출이 발생합니다. 이 시스템 호출은 상당한 오버헤드(Overhead)를 발생시켜 프로그램의 성능을 저하시킬 수 있습니다. 특히, 대용량 데이터를 처리하거나 네트워크와 통신하는 경우에 이러한 오버헤드는 큰 문제가 됩니다.
이 문제를 해결하기 위해 버퍼를 사용하는 방식이 도입되었습니다. 버퍼는 일정 크기의 메모리 공간으로, 데이터를 한 번에 미리 읽어 들여두고 필요한 경우에만 버퍼에서 꺼내 처리합니다. 이를 통해 운영체제와의 직접적인 입출력 호출을 최소화하고, 시스템 호출 횟수를 줄여 성능을 향상시킬 수 있습니다.
바이트 버퍼 스트림
BufferedInputStream과 BufferedOutputStream 클래스는 바이트 스트림에 버퍼를 추가하여 처리 성능을 높입니다. 예를 들어, 파일을 읽을 때 FileInputStream을 그대로 사용하는 대신 BufferedInputStream을 사용하면 한 번에 지정된 크기만큼 데이터를 버퍼에 읽어 둡니다. 이후 필요한 데이터는 버퍼에서 꺼내 사용하므로 운영체제와의 통신 횟수가 줄어들어 속도가 크게 향상됩니다.
예제 코드
FileInputStream fis = new FileInputStream("file.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
int data;
while ((data = bis.read()) != -1) {
System.out.print((char) data);
}
bis.close();
fis.close();
위 코드에서 BufferedInputStream은 파일에서 데이터를 한 번에 버퍼에 읽어두고, 필요할 때마다 한 바이트씩 가져옵니다. FileInputStream을 직접 사용할 때보다 성능이 향상됩니다.
문자 버퍼 스트림
문자 데이터를 다루는 경우, BufferedReader와 BufferedWriter를 사용하여 동일한 효과를 얻을 수 있습니다. 이들 클래스는 한 줄씩 데이터를 처리할 수 있는 메서드(readLine(), write())를 제공해 더욱 편리하며, 특히 텍스트 파일을 다룰 때 유용합니다.
예제 코드
FileReader fr = new FileReader("file.txt");
BufferedReader br = new BufferedReader(fr);
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
br.close();
fr.close();
위 예제에서는 BufferedReader를 사용해 한 줄씩 읽어들이고 있습니다. BufferedReader는 내부적으로 버퍼를 사용해 데이터의 입출력 효율을 높입니다.
버퍼 스트림의 장점 요약
- 성능 향상: 데이터를 한 번에 버퍼로 읽어와 처리하여 운영체제와의 입출력 호출 횟수를 줄임.
- 시스템 호출 감소: 불필요한 시스템 호출을 줄여 오버헤드를 낮춤.
- 편리한 메서드 제공: readLine()과 같은 고수준 메서드를 사용해 코드 가독성을 높이고, 문자 데이터 처리에 적합함.
버퍼 스트림은 대용량 파일이나 네트워크 통신 등 다양한 입출력 작업에서 성능을 크게 개선해줍니다. 이를 활용해 Java 입출력 성능을 최적화할 수 있습니다.