금일은 byte 단위를 사용하는 스트림의 모든 데이터를 다른 단위를 이용하여 스트림을 통해 파일에 저장하는 방법에 대해 알아보겠습니다.
public static void main(String[] args) throws IOException {
String writeString = "ABC";
// 문자 - byte UTF-8 인코딩
byte[] writeBytes = writeString.getBytes(UTF_8);
System.out.println("write String: " + writeString);
System.out.println("write bytes: " + Arrays.toString(writeBytes));
// 파일에 쓰기
FileOutputStream fos = new FileOutputStream(FILE_NAME);
fos.write(writeBytes);
fos.close();
// 파일에서 읽기
FileInputStream fis = new FileInputStream(FILE_NAME);
byte[] readBytes = fis.readAllBytes();
fis.close();
// byte -> String UTF-8 디코딩
String readString = new String(readBytes, UTF_8);
System.out.println("read bytes: " + Arrays.toString(readBytes));
System.out.println("read String: " + readString);
}

문자를 byte 숫자로 변경해야 하기 때문에 반드시 문자 집합(인코딩 셋)을 지정해야 한다
String 객체를 생성할 때, 읽어들인 byte[] 과 디코딩할 문자 집합을 전달하면 된다.
다음 예제는 스트림에 byte 대신에 문자를 저장하고 읽을 수 있는 기능의 예제입니다.
// 파일에 쓰기
FileOutputStream fos = new FileOutputStream(FILE_NAME);
OutputStreamWriter osw = new OutputStreamWriter(fos, UTF_8);
osw.write(writeString);
osw.close();
// 파일에서 읽기
FileInputStream fis = new FileInputStream(FILE_NAME);
InputStreamReader isr = new InputStreamReader(fis, UTF_8);
StringBuilder content = new StringBuilder();
int ch;
while ((ch = isr.read()) != -1) {
content.append((char) ch);
}
isr.close();
OutputStreamWriter 는 문자를 입력 받고, 받은 문자를 인코딩해서 byte[] 로 변환한다.
osw.write(writeString) 를 보면 String 문자를 직접 전달하는 것을 확인할 수 있다.
데이터를 읽을 때는 int ch = read() 를 제공하는데, 여기서는 문자 하나인 char 형으로 데이터를 받게 된
다. 그런데 실제 반환 타입은 int 형이므로 char 형으로 캐스팅해서 사용하면 된다.
OutputStreamWriter, InputStreamReader 의 부모는 Reader, Writer 를 상속받고 있습니다.
자바는 byte를 다루는 I/O 클래스와 문자를 다루는 I/O 클래스를 둘로 나누어두었다.
문자를 다루는 클래스는 Writer , Reader 의 자식이다.
부모 클래스의 기본 기능은 String , char 같은 문자를 다룬다
결과적으로 내부에서 지정된 문자 집합을 사용해서 문자를 byte 로 인코딩해서 저장하는것은 변함이 없습니다.
FileReader, FileWirter
FileWriter fw = new FileWriter(FILE_NAME, UTF_8);
fw.write(writeString);
fw.close();
// 파일에서 읽기
StringBuilder content = new StringBuilder();
FileReader fr = new FileReader(FILE_NAME, UTF_8);
int ch;
while ((ch = fr.read()) != -1) {
content.append((char) ch);
}
fr.close();
FileWriter 에 파일명과, 문자 집합(인코딩 셋)을 전달한다.
FileWriter 는 사실 내부에서 스스로 FileOutputStream 을 하나 생성해서 사용한다.
변함 없는 것은 문자를 byte로 변경하려면 항상 문자 집합(인코딩 셋)이 필요하다
Reader , Writer 에도 버퍼 보조 기능을 제공하
는 BufferedReader , BufferedWriter 클래스가 있다.
BufferedReader 는 한 줄 단위로 문자를 읽는 기능도 추가로 제공한다
// 파일에 쓰기
FileWriter fw = new FileWriter(FILE_NAME, UTF_8);
BufferedWriter bw = new BufferedWriter(fw, BUFFER_SIZE);
bw.write(writeString);
bw.close();
// 파일에서 읽기
StringBuilder content = new StringBuilder();
FileReader fr = new FileReader(FILE_NAME, UTF_8);
BufferedReader br = new BufferedReader(fr, BUFFER_SIZE);
String line;
while ((line = br.readLine()) != null) {
content.append(line).append("\n");
}
br.close();
몇가지 유용한 부가 기능을 제공하는 PrintStream , DataOutputStream 보조 스트림을 알아보겠습니다.
PrintStream 은 우리가 자주 사용해왔던 바로 System.out 에서 사용되는 스트림이다.
PrintStream 과 FileOutputStream 을 조합하면 마치 콘솔에 출력하듯이 파일에 출력할 수 있다
FileOutputStream fos = new FileOutputStream("temp/print.txt");
PrintStream printStream = new PrintStream(fos);
printStream.println("hello java!");
printStream.println(10);
printStream.printf("hello %s", "world");
printStream.close();
DataOutputStream 을 사용하면 자바의 String , int , double , boolean 같은 데이터 형을 편리하게 다룰수 있다.
FileOutputStream 을 조합하면 파일에 자바 데이터 형을 편리하게 저장할 수 있다.
FileOutputStream fos = new FileOutputStream("temp/data.dat");
DataOutputStream dos = new DataOutputStream(fos);
dos.writeUTF("회원A");
dos.writeInt(20);
dos.writeDouble(10.5);
dos.writeBoolean(true);
dos.close();
FileInputStream fis = new FileInputStream("temp/data.dat");
DataInputStream dis = new DataInputStream(fis);
System.out.println(dis.readUTF());
System.out.println(dis.readInt());
System.out.println(dis.readDouble());
System.out.println(dis.readBoolean());
dis.close();
주의할 점으로는 저자한 순서의 타입으로 읽어야 한다는 것입니다.
writeUTF() 의 경우 UTF-8 형식으로 저
장하지만, 나머지의 경우 문자가 아니라 각 타입에 맞는 byte 단위로 저장하기 때문이다.