자바에서 파일의 내용을 읽고 쓰는 클래스는?
FileReader
FileWriter
파일에서 데이터를 읽기 위한 클래스는?
자바의 기본적인 데이터 입출력은 java.io 패키지가 기능을 제공한다.
여기서 다룰 파일로부터 데이터 입출력은 FileReader, FileWriter 클래스가 담당한다.
FileReader is meant for reading streams of characters.
FileReader 클래스는 문자 기반 스트림을 읽는다.
문자 기반 스트림
자바에서 스트림은 기본적으로 바이트 단위로 데이터를 전송합니다.
하지만 자바에서 가장 작은 타입인 char 형이 2바이트이므로, 1바이트씩 전송되는 바이트 기반 스트림으로는 원활한 처리가 힘든 경우가 있습니다.
따라서 자바에서는 바이트 기반 스트림뿐만 아니라 문자 기반의 스트림도 별도로 제공합니다.
이러한 문자 기반 스트림은 기존의 바이트 기반 스트림에서 InputStream을 Reader로, OutputStream을 Writer로 변경하면 사용할 수 있습니다. ( 출처 : TCP School )
파일 입출력 과정
3단계로 진행된다.
1 단계 : open File ===> 2 단계 : read File or write File ===> 3 단계 : close File
각 단계를 코드로 보자,
1 단계) 파일 열기.
FileReader reader = new FileReader("poem.txt");
파라미터로 File file, FileDescriptor fd, String fileName 중 하나를 반드시 넘겨줘야 객체가 생성된다.
파일을 찾지 못하는 경우를 대비해 예외처리가 필요하다.
2 단계) 파일 읽기.
슈퍼 클래스 메서드인 read()로 파일의 데이터를 읽는다. 주의할 점은 파일에서 문자 하나씩 리턴해준다.
int data = reader.read();
반복문으로 -1이 반환될 때까지 reader.read();를 계속 수행해준다.
파일에 있는 문자를 모두 리턴하면 마지막으로 -1을 리턴한다.
왜 -1 을 리턴할까? 자바의 char 타입은 unsigned, 즉 부호가 없다. 표현 범위가 0 ~ 2^16 -1 이다. 그래서 문자를 모두 리턴하고 나면 char 표현 범위가 될 수 없는 -1을 리턴해줌으로써 문자 읽기가 끝났다는 것을 알려준다. |
이런 이유로 reader.read()에서 리턴되는 값을 받는 변수의 data의 타입이 int형이 된다.
3 단계) 파일 닫기
reader.close( );
이제 전체 코드를 보자.
import java.io.*;
public class ReaderExample01 {
public static void main(String[] args) {
FileReader reader = null;
try {
reader = new FileReader("poem.txt"); // 파일 읽기
while(true) { // -1이 반환될 때까지 문자 읽기
int data = reader.read();
if(data == -1)
break;
char ch = (char)data;
System.out.println(ch);
}
}
catch (FileNotFoundException fnfe) { // 파일이 없는 경우 예외처리
System.out.println();
}
catch (IOException ioe) {
System.out.println("cannot read a file"); // 데이터를 읽을 수 없는 경우 예외처리
}
finally {
try {
reader.close();
}
// 코드가 실행되는 동안 파일이 삭제 or 경로 변경으로 close() 할 수 없는 경우 예외 처리
catch(Exception e) {
System.out.println("file not found");
}
}
}
}
눈여겨 봐야할 코드
1. FileReader reader = null;
레퍼런스 타입 변수 reader가 try 블록, finally 블록에서 호출된다.
만일 try 블록 안에서 변수 선언을 해준다면
reader 변수는 try 블록이 밖에서는사용할 수 없다.
즉, finally 블록에서 reader.close(); 를 수행할 수 없다.
2. finally { ... }
reader.close(); 코드가 finally 블록에 있어야 한다.
try 블록에 마지막 줄에 코드를 옮겼다 가정해보자.
while문에서 예외가 발생하면 catch문이 호출되고 프로그램은 종료된다.
이때 reader.close();에는 절대 도달할 수 없다.
자바가 알아서 도달할 수 없는 코드라고 경고 메세지를 줄 것이다.
FileReader가 여러 문자를 한 번에 읽을 순 없을까?
인간은 효율을 극도로 추구한다. 여러 문자를 한 번에 읽을 수 있는 방법이 있다.
바로 배열을 사용하는 것이다.
char arr [ ] = new char [100];
int num = reader.read(arr);
read() 메서드에 char 타입의 배열을 파라미터로 넘겨준다.
int num에는 실제로 읽은 문자의 갯수가 반환된다.
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class ReaderExample02 {
public static void main(String[] args) {
FileReader reader = null;
try {
reader = new FileReader("poem.txt");
char arr [] = new char [100]; // 문자를 담을 char 타입의 배열 생성
int num = reader.read(arr);
System.out.println(arr); // 배열을 출력하면 파일의 내용이 출력된다.
}
catch(FileNotFoundException fnfe) {
System.out.println();
}
catch(IOException ioe) {
System.out.println("cannot read a file");
}
finally {
try {
reader.close();
}
catch(Exception e) {
System.out.println("error");
}
}
}
}
반복문 없이 배열만 출력하면 poem.txt 파일의 내용이 출력된다!
FileWriter 역시 같은 흐름으로 사용된다.
import java.io.FileWriter;
import java.io.IOException;
public class WriterExample01 {
public static void main(String[] args) {
FileWriter writer = null;
try {
writer = new FileWriter("output.txt"); // 해당 파일이 없으면 생성해준다.
char arr [] = {'a','p','p','l','e', ' ', 'i','s', ' ', 't', 'h', 'e', ' ', 'b', 'e', 's', 't'};
for(int cnt = 0; cnt < arr.length; cnt++) {
writer.write(arr[cnt]); // 한 문자씩 차례대로 입력
}
}
catch(IOException ioe) {
System.out.println("cannot ouput file");
}
finally{
try {
writer.close();
}
catch(Exception e) {
System.out.println("close error");
}
}
}
}
'Programming > Java' 카테고리의 다른 글
[ Java ] - 입력 스트립 ( Input Stream)과 출력 스트림 ( Output Stream ) (0) | 2020.09.22 |
---|---|
[ Java ] - objectInputStream, objectOutputStream (0) | 2020.09.22 |
[ Java ] - 난수 생성하기 (0) | 2020.09.22 |
[ Java ] - 시간을 나타내기 (0) | 2020.09.22 |
[ Java ] - 접근 제어자 (0) | 2020.09.21 |
댓글