02. 문자 스트림과 텍스트 파일 입출력
문자 스트림은 문자를 단위로 다루는 스트림으로, 문자가 아닌 바이너리 값들은 제대로 처리하지 못한다. 텍스트 파일은 문자로만 구성된 파일로서, 텍스트 파일을 읽고 쓰기 위해서는문자 입출력 시스템을 사용해야 한다. 문자 스트림 파일 입출력 클래스인 FileReader/FileWriter를 이용해서 텍스트 파일을 읽고 쓰는 방법에 대해서 알아봅시다.
텍스트 파일 읽기
- 파일입력 스트림 생성 ( 파일 열기)
: 파일을 읽기 위해, 우선 파일 입력 스트림을 생성하고 파일과 연결한다.
FileReader fin = new FileReader("c:\\test.txt"); FileReader의 생성자는 스트림 객체를 생성한 후 c:\test.txt 파일을 찾아 열고, 파일과 스트림을 연결한다.
- 파일 읽기
: 이제 fin 스트림을 이용하여 파일을 읽어보자. fin.read()는 파일로부터 문자 하나를 읽어 리턴하며, 파일의 끝(EOF)를 만나면 -1을리턴한다. fin.read()를 이용하여 파일 전체를 읽어 화면에 출력하는 코드를 보자.
int c; while((c = fin.read()) != -1) { System.out.println((char)c);}
c = fin.read()를 읽을때 int타입을 이용하는 이유는 int타입으로 반환해야 값의 구분이 명확하기 때문이다. 파일이 큰 경우 한 번에 한 문자씩 읽으면 읽는 속도가 너무 느리기 때문에, 다음과 같이 read()를 이용하여 배열buf의 크기만큼 한 번에 한 블록씩 읽을 수 있다.
char [] buf = new char[1024];
int n = fin.read(buf); read()는 실제로 읽은 문자수를 리턴하므로, n이 버퍼의 크기보다 작다면 파일의 끝까지 읽은 것으로 판단한다.
- 스트림 닫기
: 스트림이 더 이상 필요 없게 되면 닫아야 한다. close() 메소드를 호출하면 스트림을 닫으며, 닫힌 스트림으로부터는 더 이상 읽을 수 없다. fin.close();
FileReader의 생성자
- FileReader(File file) : file에 지정된 파일로부터 읽는 FileReader 생성. File클래스 타입에는 파일경로가 포함되어있다.
- FileReader(String name) : name 이름의 파일로부터 읽는 FileReader 생성
FileReader의 주요 메소드
- int read() : 한 개의 문자를 읽어 정수형으로 리턴 (잘 안쓴다)
- int read(char[] cbuf) : 최대 cbuf 배열의 크기만큼 문자들을 읽어 cbuf 배열에 저장. 만일 읽는도중 EOF를 만나면 실제 읽은 문자 개수 리턴. 타입이 배열이므로 크기가 고정되어 있다. 이미지 읽을 때 주로 사용한다.
- int read(char[] cbuf, int off, int len) : 최대 len 크기만큼 읽어 cbuf 배열의 off부터 저장. 읽는 도중 EOF를 만나면 실제읽은 문자 개수 리턴. 구간을 지정해서 읽을 때 사용한다.
- String getEncoding() : 스트림이 사용하는 문자 집합의 이름 리턴 ( 참고만 하기)
- void close() : 입력 스트림을 닫고 관련된 시스템 자원 해제. 종료하지 않으면 메모리 공간이 부족해져서 서버가 펑!
파일 입출력과 예외 처리
파일 입출력 실행 중 예외가 발생할 수 있다. 첫째, 파일의 경로명이 틀리거나, 어떤 상황으로 파일을 열 수 없는 경우, FileReader 생성자는 FileNotFoundException 예외를 발생시킨다.
FileReader fin = new FileReader("c:\\test.txt"); // FileNotFoundException 발생가능
둘째, 파일 읽기, 쓰기, 닫기를 하는 동안 디스크 오작동이나 파일이 꺠진 경우등으로 인해 입출력 오류가 발생하면 read(), write(), closd() 메소드는 IOException 예외를 발생시킨다.
int c = fin.read() // IOException 발생가능
그러므로 파일 입출력 코드에는 반드시 입출력 코드 전체를 감싸는 try-catch 블록이 필요하다. ( 컴파일러가 알려줌! )
텍스트 파일 쓰기
FileWriter를 이용하여 파일 출력 스트림을 만들고, 텍스트를 파일에 저장하는 방법을 알아봅시다.
- 파일출력 스트림 생성
: c:\temp\test.txt 파일에 텍스트는 출력 스트림 생성하기
FileWriter fout = new FileWriter("c:\\temp\\test.txt");
FileWriter의 생성자는 스트림 객체를 생성한 후, c:\temp\test.txt 파일을 열어 스트림과연결한다. 파일이 없는 경우 빈 파일을 생성하며, 이미 파일이 있는 경우 파일 내용을 지우고 파일의처음부터 쓰기가 진행된다.
- 파일쓰기
: 이제 fout 스트림의 write() 메소드를 이용하여 텍스트를 파일에 기록할 수 있다. 문자 하나씩 기록하거나, 한번에 한 블록씩 쓸 수 있다.
fout.write('A'); // 문자 'A'를 파일에 기록
char[] buf = new char [1024];
fout.write(buf, 0, buf.length); // buf[0] 부터 buf의 크기만큼 쓰기
- 스트림 닫기
: 텍스트를 모두 파일에 기록하였으면 close를 호출하여 스트림을 닫는다. 스트림을 닫으면 연결된 파일도 닫힌다.
fout.closd();
FileWriter의 생성자
- FileWriter(File file) : file에 데이터를 저장할 FileWriter 생성 // File클래스에 경로가 포함
- FileWriter(String name) : name 파일에 데이터를 저장할 FileWriter 생성 // 직접적으로 경로 쓰기
- FileWriter(File file, boolean append) = FileWriter (String name , boolean append) : FileWriter를 생성하며, append가 true이면 파일의 마지막부터 데이터 저장, false이면 기존 데이터를 삭제 하고 처음부터 저장(=덮어쓰기)
FileWriter의 메소드
- void write (int c) : c를 char로 변환하여 한 개의 문자 출력
- void write (String str) : 문자열 str 출력
- void write (String str, int off, int len) : 인덱스 off부터 len개의 문자를 str 문자열에서 출력
- void write (char [] cbuf, int off, int len) : 인덱스 off부터 len개의 문자를 배열 cbuf에서 출력
- void flush() : 스트림에 남아 있는 텍스트 모두 출력
- String getEncoding() : 스트림이 사용하는 문자 집합의 이름 리턴
- void close() : 출력 스트림을 닫고 관련된 시스템 자원 해제