[자바 - 고급 2편, I/O, 네트워크, 리플렉션] I/O 기본2
문자 다루기1 - 시작
스트림의 모든 데이터는 byte 단위를 사용한다. 따라서 byte 가 아닌 문자를 스트림에 직접 전달할 수 는 없다. 예를 들어서 String 문자를 스트림을 통해 파일에 저장하려면 String 을 byte 로 변환한 다음에 저장해야 한다.
예제를 위한 공통 상수를 만든다.
public class TextConst {
public static final String FILE_NAME = "temp/hello.txt";
}
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import static io.text.TextConst.FILE_NAME;
import static java.nio.charset.StandardCharsets.UTF_8;
public class ReaderWriterMainV1 {
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(writeBytes));
System.out.println("read String: " + readString);
}
}
실행 결과
write String: ABC
write bytes: [65, 66, 67]
read bytes: [65, 66, 67]
read String: ABC
실행 결과 - hello.txt
ABC
문자 다루기2 - 스트림을 문자로
OutputStreamWriter: 스트림에 byte 대신에 문자를 저장할 수 있게 지원한다.InputStreamReader: 스트림에 byte 대신에 문자를 읽을 수 있게 지원한다.
import java.io.*;
import static io.text.TextConst.FILE_NAME;
import static java.nio.charset.StandardCharsets.UTF_8;
public class ReaderWriterMainV2 {
public static void main(String[] args) throws IOException {
String writeString = "ABC";
System.out.println("write String: " + writeString);
// 파일에 쓰기
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();
System.out.println("read String: " + content);
}
}
실행 결과
write String: ABC
read String: ABC
OutputStreamWriter

InputStreamReader

문자 다루기3 - Reader, Writer
자바는 byte를 다루는 I/O 클래스와 문자를 다루는 I/O 클래스를 둘로 나누어두었다.
OutputStreamWriter는 바로 문자를 다루는Writer클래스의 자식이다.
그래서write(String)이 가능한 것이다.OutputStreamWriter는 문자를 받아서 byte로 변경한 다음에 byte를 다루는OutputStream으로 데이터를 전달했던 것이다.
byte를 다루는 클래스

문자를 다루는 클래스

FileWriter, FileReader
Writer,Reader를 사용하는 다른 예,FileWriter는 생성자 내부에서 대신FileOutputStream를 생성해준다.
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import static io.text.TextConst.FILE_NAME;
import static java.nio.charset.StandardCharsets.UTF_8;
public class ReaderWriterMainV3 {
public static void main(String[] args) throws IOException {
String writeString = "ABC";
System.out.println("write String: " + writeString);
// 파일에 쓰기
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();
System.out.println("read String: " + content);
}
}
실행 결과
write String: ABC
read String: ABC
정리
Writer,Reader클래스를 사용하면 바이트 변환 없이 문자를 직접 다룰 수 있어서 편리하다. 하지만 실제로는 내부에서 byte로 변환해서 저장한다는 점을 기억하자.
문자 다루기4 - BufferedReader
Reader,Writer에도 버퍼 보조 기능을 제공하는BufferedReader,BufferedWriter클래스가 있다.BufferedReader는 한 줄 단위로 문자를 읽는 기능도 추가로 제공한다.
import java.io.*;
import static io.text.TextConst.FILE_NAME;
import static java.nio.charset.StandardCharsets.UTF_8;
public class ReaderWriterMainV4 {
private static final int BUFFER_SIZE = 8192;
public static void main(String[] args) throws IOException {
String writeString = "ABC\n가나다";
System.out.println("== Write String ==");
System.out.println(writeString);
// 파일에 쓰기
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();
System.out.println("== Read String ==");
System.out.println(content);
}
}
실행 결과
== Write String == ABC
가나다
== Read String == ABC
가나다
기타 스트림
PrintStream
PrintStream은 우리가 자주 사용해왔던 바로System.out에서 사용되는 스트림이다.PrintStream과FileOutputStream을 조합하면 마치 콘솔에 출력하듯이 파일에 출력할 수 있다.
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
public class PrintStreamEtcMain {
public static void main(String[] args) throws FileNotFoundException {
FileOutputStream fos = new FileOutputStream("temp/print.txt");
PrintStream printStream = new PrintStream(fos);
printStream.println("hello java!");
printStream.println(10);
printStream.println(true);
printStream.printf("hello %s", "world");
printStream.close();
}
}
실행 결과 - temp/print.txt**
hello java!
10
true
hello world
DataOutputStream
DataOutputStream을 사용하면 자바의String,int,double,boolean같은 데이터 형을 편리하게 다룰 수 있다. 이 스트림과FileOutputStream을 조합하면 파일에 자바 데이터 형을 편리하게 저장할 수 있다.
주의 : 꼭! 저장한 순서대로 읽어야 한다.
import java.io.*;
public class DataStreamEtcMain {
public static void main(String[] args) throws IOException {
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();
}
}
실행 결과
회원A
20
10.5
true
정리
- 기본(기반, 메인) 스트림
- File, 메모리, 콘솔등에 직접 접근하는 스트림
- 단독으로 사용할 수 있음
- 예)
FileInputStream,FileOutputStream,FileReader,FileWriter,ByteArrayInputStream,ByteArrayOutputStream
- 보조 스트림
- 기본 스트림을 도와주는 스트림
- 단독으로 사용할 수 없음, 반드시 대상 스트림이 있어야함
- 예)
BufferedInputStream,BufferedOutputStream,InputStreamReader,OutputStreamWriter,DataOutputStream,DataInputStream,PrintStream