문자 I/O

sungs·2025년 8월 5일

자바

목록 보기
55/95

문자 I/O

기본적으로 스트림은 바이트 단위만 받기 때문에 문자를 직접 보낼 수는 없다. 따라서 getBytes()로 인코딩하거나 new String(byte[], 문자 조합)으로 디코딩을 해야한다. 다만, 이러한 작업을 간편하게 해주는 메서드들이 존재한다.

OutputStreamWriter, InputStreamReader

Buffered처럼 OutputStreamWriter osw = new OutputStreamWriter(fos, UTF_8);/ InputStreamReader isr = new InputStreamReader(fis, UTF_8);으로 각각 스트림에 연결해서 write/read 해주면 된다. 얘네들은 스트림이 아닌 Writer/Reader를 상속받는다. 이를 통하면 자동으로 지정된 문자조합으로 인코딩/디코딩 해준다. 여기서 더 줄일 수 있는데 그게 바로 FileWriter, FileReader이다.

FileWriter, FileReader

스트림을 생성하지 않고 바로 문자를 파일에 쓰고 읽어올 수 있게 해준다. new FileWriter(FILE_NAME, UTF_8)/new FileReader(FILE_NAME, UTF_8) 이렇게 문자 조합과 파일 이름을 넣어주고 write/read를 해주면 된다. 안에 각각 스트림에 존재해 스트림을 생성하는 코드를 생략할 수 있는 것이다. read하면 문자 그대로 반환해준다.

BufferedWriter, BufferedReader

버퍼로 담아 한 번에 보내거나 읽어올 수도 있다.

import java.io.*;

public class BufferedExample {
    public static void main(String[] args) {
        String fileName = "test.txt";
        
        // 1. BufferedWriter를 사용하여 파일에 데이터 쓰기
        System.out.println("파일에 데이터 쓰는 중...");
        try (BufferedWriter bw = new BufferedWriter(new FileWriter(fileName))) {
            bw.write("안녕하세요, BufferedWriter 예제입니다.");
            bw.newLine(); // 줄바꿈
            bw.write("이것은 두 번째 줄입니다.");
            System.out.println("파일 쓰기 완료!");
        } catch (IOException e) {
            e.printStackTrace();
        }

        System.out.println("---");
        
        // 2. BufferedReader를 사용하여 파일에서 데이터 읽기
        System.out.println("파일에서 데이터 읽는 중...");
        try (BufferedReader br = new BufferedReader(new FileReader(fileName))) {
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
            System.out.println("파일 읽기 완료!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

이렇게 Writer, Reader에 연결시켜 사용할 수 있다. 몇 줄의 문장을 내보내거나 읽어올 수 있다. readline은 한 줄 단위로 읽어오고 -1 대신 null을 반환한다.

PrintStream

이를 사용하면 println을 이용해 콘솔에 문장을 출력하듯이 파일에 출력할 수 있다.

import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.io.IOException;

public class PrintStreamExample {
    public static void main(String[] args) {
        String fileName = "printstream_output.txt";
        
        // PrintStream을 사용하여 파일에 데이터 쓰기
        try (PrintStream ps = new PrintStream(new FileOutputStream(fileName))) {
            
            // 다양한 타입의 데이터를 println으로 출력
            ps.println("--- PrintStream 예제 ---");
            
            // 문자열 출력
            String message = "안녕하세요, PrintStream입니다.";
            ps.println(message);
            
            // 정수 출력
            int number = 12345;
            ps.println("숫자: " + number);
            
            // 실수 출력
            double pi = 3.14159;
            ps.println("파이 값: " + pi);
            
            // boolean 값 출력
            boolean isTrue = true;
            ps.println("논리값: " + isTrue);
            
            System.out.println("데이터가 성공적으로 파일에 기록되었습니다: " + fileName);
            
        } catch (IOException e) {
            System.err.println("파일을 쓰는 도중 오류가 발생했습니다: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

DataOutputStream

이를 사용하면 String, boolean, int 등 다양한 데이터 유형을 편리하게 관리할 수 있다.

import java.io.*;

public class DataStreamExample {
    public static void main(String[] args) {
        String fileName = "data.bin";

        // 1. DataOutputStream으로 다양한 타입의 데이터 파일에 쓰기
        System.out.println("데이터를 파일에 쓰는 중...");
        try (DataOutputStream dos = new DataOutputStream(new FileOutputStream(fileName))) {
            
            // 정수(int) 쓰기
            dos.writeInt(12345);
            
            // 실수(double) 쓰기
            dos.writeDouble(3.14159);
            
            // boolean 값 쓰기
            dos.writeBoolean(true);
            
            // UTF-8 인코딩된 문자열 쓰기
            dos.writeUTF("안녕하세요, DataStream 예제입니다.");

            System.out.println("파일 쓰기 완료!");

        } catch (IOException e) {
            e.printStackTrace();
        }
        
        System.out.println("---");

        // 2. DataInputStream으로 파일에서 데이터 읽기
        System.out.println("데이터를 파일에서 읽는 중...");
        try (DataInputStream dis = new DataInputStream(new FileInputStream(fileName))) {

            // 쓴 순서대로 읽기
            int intValue = dis.readInt();
            double doubleValue = dis.readDouble();
            boolean booleanValue = dis.readBoolean();
            String stringValue = dis.readUTF();

            System.out.println("읽어온 정수: " + intValue);
            System.out.println("읽어온 실수: " + doubleValue);
            System.out.println("읽어온 boolean: " + booleanValue);
            System.out.println("읽어온 문자열: " + stringValue);
            
            System.out.println("파일 읽기 완료!");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

각각 스트림에 연결해 사용할 수 있다. 다만 파일에서는 writeUTF 빼고는 내용을 볼 수 없다. 자바를 기준으로 하는 byte 형태로 그대로 들어가기 때문이다.
그로 인해 분서 편집기는 이상한 문자를 출력할 수밖에 없다.

정확히는 바이트를 사용해 문자 앞에 그 문자의 글자수를 적어 놓고 저장한다. 예를 들어 name이라하면 2바이트를 사용해서 4name이라는 형식으로 파일에 저장된다. 물론 여전히 바이트 형태라 사람이 파일에서 직접 확인할 수는 없다.

이를 통해 데이테 유형별로 딱딱 잘라서 읽어올 수 있기 때문에 Write/Reader일 때 읽어온 다음 split으로 구분자로 나눠서 그걸 리스트에 집어 넣었던 것과 달리 데이터 유형대로 끊어서 편리하게 입출력할 수 있다. 게다가 바이트도 덜 사용한다. 데이터 유형에 맞춰지므로 전부 String으로 취급받는다는 점도 해결된다.

profile
앱 개발 공부 중

0개의 댓글