K-DigitalTraining 강의/1. Java

[5주차] 85. 텍스트를 파일을 저장하기 위한 FileOutputStream / FileWriter / BufferedWriter 차이점

이대곤 2022. 6. 8. 09:51

FileOutputStream / FileWriter / BufferedWriter 

위 세가지는 공통적으로 파일에 텍스트를 저장하기 위한 용도로 사용된다.

 

먼저, FileOutputStream은 1byte 단위로 처리하며, 버퍼가 없어 write()시 바로 디스크에 쓰기위한 시스템 콜이 이뤄진다.
flush()나 close()를 만나지 않아도 
1글자 마다 디스크에 접근하기 때문에 효율이 가장 떨어진다. 1byte 단위로 전송하기 때문에 한글은 깨지며 영어 숫자 특수문자는 잘된다.

 

바로 다음에 오는 링크는 버퍼를 사용하지 않고 텍스트를 파일에 저장하는 FileOutputStream 을 설명한 그림이다.

https://hajsoftutorial.com/java/wp-content/uploads/2018/04/Unbuffered.gif

아래는 그 반대의 경우인 버퍼를 사용하여 저장하는 경우를 보여주는 것이다.

https://hajsoftutorial.com/java/wp-content/uploads/2018/04/bufferedoutput.gif

 

아래는 버퍼 사용유무 상관없이 텍스트를 파일에 쓸 수 있는 클래스들의 효율을 비교한 차트이다.

당연히 1글자마다 디스크에 쓰기 작업을 수행하는 시스템 콜을 하는 FileOutputStream이 가장 느리다.

 

Comparison of the times needed to write 100 million bytes/characters to a file

https://www.happycoders.eu/java/how-to-write-files-quickly-and-easily/

 

FileOutputStream / FileWriter / BufferedWriter 

FileWriter, BufferedWriter는 모두 텍스트를 파일에 저장하기 위한 용도라서 기능은 거의 같고 

사용가능한 메소드만 살짝 다르다. 둘 다 버퍼를 사용하지만, 효율면에서는 BufferedWriter가 더 좋다.

 

FileWriter에는 Buffered 라는 단어가 안 붙어있지만 얘 또한 내부적으로 버퍼를 사용하고 있다. FileWriter를 사용해 close()를 만나야 파일에 내용이 들어가는걸 보면 얘도 버퍼를 사용하고 있는게 아닌가 싶었는데, 클래스 설명을 보니 얘도 내부적으로 버퍼를 사용하고 있다. "FileWriter : Writes text to character files using a default buffer size."

FileWriter/BufferedWriter 둘 다 기본 사이즈가 8192bytes(characters)인 버퍼를 가진다고 한다.

 

FileWriter는 OutputStreamWriter을 상속받는데 write() 메소드도 여기서 상속받은 것이다. API문서를 보면 OutputStreamWriter의 write()메소드는 호출될 때 마다 주어진 문자열에 대해 인코딩 변환기가 호출된다고 하는데, 변환된 결과 바이트는 기본 출력 스트림에 쓰기 전에 버퍼에 누적된다고 한다. 무튼  write()메소드는 호출될 때 마다 주어진 문자열에 대해 인코딩 변환기가 호출되는데 이를 피하고 싶다면 BufferedWriter 내에 래핑하는 것을 고려하라고 한다. 이제보니 둘의 성능차이는 여기서 오는 듯 하다. (https://docs.oracle.com/javase/7/docs/api/java/io/OutputStreamWriter.html)

 

다음에 오는 그림은 버퍼를 사용하는 메소드(클래스)만 비교한 것으로

100,000,000 bytes 를 파일에 저장하는데 걸리는 시간을 나타낸 비교 결과이다.

성능상 BufferedWriter 가 우위에 있는것을 알 수 있다.

 

Comparison of the times needed to write 100 million bytes/characters to a file (buffered)

https://www.happycoders.eu/java/how-to-write-files-quickly-and-easily/

FileWriter / BufferedWriter 코드상의 차이

* BufferedWriter 객체는 FileWriter의 객체를 통해서만 만들 수 있음

FileWriter file = new FileWriter("foo.txt");
file.write("foobar");
file.close();
FileWriter file = new FileWriter("foo.txt");
BufferedWriter bf = new BufferedWriter(file);
bf.write("foobar");
bf.close();

BufferedWriter가 효율성을 증대시키는 경우

BufferedWriter 는 다음의 상황일 때 효율적이라고 한다.

case1. 여러개의 write들이 있는 경우

case2. 버퍼 사이즈에 비해 write들의 사이즈가 작은경우 -> 버퍼에 모아모아 다 차면 파일에 쓰는 호출이 그때서야 이뤄지므로

 

아래는 여러번의 small writes 를 하는 경우, BufferedWriter가 효율성을 증대시키는 경우이다.

버퍼의 크기가 다 채워지거나  flush() 되거나 close()를 만나거나 일 때만, 파일에 쓰여지는 호출이 이뤄진다.

FileWriter file = new FileWriter("foo.txt");
BufferedWriter bf = new BufferedWriter(file);

for(int i = 0; i < 100; i++) {
    bf.write("foorbar");
    bf.write(NEW_LINE);
}
bf.close();