최원종의 개발 블로그

문자 기반 스트림(키보드, 콘솔, 파일) 본문

Java/JAVA 유용한 클래스

문자 기반 스트림(키보드, 콘솔, 파일)

chl6698 2026. 3. 24. 14:05

바이트 스트림으로 한글 파일 읽으면 글자가 깨지는 이유

한글 '안' 을 UTF-8 로 표현하면 → 3바이트 [0xEC, 0x95, 0x88] 
// 0x 가 붙으면 16진수(Hexadecimal) 표기입니다.

FileInputStream 은 1바이트씩 읽음
→ '안' 이 세 조각으로 잘려서 따로따로 읽힘
→ 각 조각을 (char) 로 변환하면 의미없는 문자가 출력됨

문자 스트림은 '안' 이 3바이트라는 것을 알고 통째로 읽음
→ '안' 이 정상 출력됨
파일에서 읽을 때는 3바이트이지만, 자바 프로그램 안에서는 char 2바이트로 변환되어 처리됩니다.

바이트 스트림 vs 문자 스트림

바이트 스트림   InputStream / OutputStream  →  1바이트 단위, 한글 깨짐 위험
문자 스트림     Reader / Writer             →  1문자(char) 단위, 한글 자동 처리
 FileInputStream / FileOutputStream 은 바이트 기반
 는 FileReader / FileWriter 는 문자 기반 버전
 FileInputStream  →  FileReader   (읽기, 바이트 → 문자)
FileOutputStream →  FileWriter   (쓰기, 바이트 → 문자)

-코드

package io.ch16;

import java.io.FileReader;
import java.io.FileWriter;

public class FileStreamBasic {

    public static void main(String[] args) {
        writeToFile("basic_output.txt");
        System.out.println("-----------------");
        readFromFile("basic_output.txt");

    } // end of main

    // 파일에 텍스트를 쓰는 메서드 (문자 기반 스트림 사용)
    public static void writeToFile(String fileName) {
        /**
         * FileWriter 는 문자 기반 출력 스트림입니다.
         * FileOutputStream과  fos.write(byte[])  달리 write(String) 이 가능합니다.
         * getBytes() 변환이 필요가 없습니다.
         */
        // append 모들 설정하지 않으면 기본값이 false 이다.
        try (FileWriter writer = new FileWriter(fileName)) {
            String text = "자바 문자 기반 스트림 예제\n";
            // text.getBytes() 이거 할 필요 없이
            writer.write(text);
            writer.write("추가 문자열을 기록 합니다");
            // writer.flush(); 생략 가능한
            System.out.println("파일에 텍스트를 잘 기록 하였습니다");
        } catch (Exception e) {
            System.err.println("파일 쓰기 중 오류 발생 : " + e.getMessage());
        }
    }

    public static void readFromFile(String fileName) {
        /**
         * FileReader 는 문자 기반 입력 스트림입니다.
         * read() 는 한 문자씩 읽어 유니코드 값(정수)으로 반환합니다.
         * FileInputStream과 사용법은 같지만 한글이 깨지지 않습니다.
         */
        try (FileReader reader = new FileReader(fileName)) {

            int charCode;
            while ( (charCode = reader.read()) != -1) {
                System.out.print((char) charCode);
            }
        } catch (Exception e) {
            System.out.println("해당하는 파일이 없습니다 : " + e.getMessage());
        }
    }

}

- FileOutputStream vs FileWriter 핵심 차이

// FileOutputStream - String 직접 불가, getBytes() 변환 필요
try (FileOutputStream fos = new FileOutputStream("output.txt")) {
    fos.write("안녕하세요".getBytes("UTF-8")); // 변환 필요
}

// FileWriter - String 바로 write 가능, 한글 자동 처리
try (FileWriter fw = new FileWriter("output.txt")) {
    fw.write("안녕하세요"); // 변환 불필요, 한글 정상 저장
}

-InputStreamReader(바이트를 문자로 변환)

System.in 은 InputStream (바이트 기반)

System.in.read()는 한글을 처리하지 못함

InputStreamReader 는 바이트 스트림을 문자 스트림으로 변환해 주는 역할

[키보드] → System.in (바이트) → InputStreamReader → 프로그램
                              (바이트 → 문자 변환)

 


-코드

package io.ch16;

import java.io.InputStreamReader;
import java.io.PrintWriter;

/**
 // * 바이트 단위 스트림 이름 형태 : InputStream, OutputStream
 * 문자 기반 스트림 이름 형태 : xxxReader, xxxWriter
 */
public class KeyboardConsoleStream {

    public static void main(String[] args) {
        /**
         *  InputStreamReader 의 read() 는 하나의 문자를 읽어서
         *  유니코드(정수값)로 반환 합니다.
         *  PrintWriter는 문자 기반의 출력 스트림입니다.
         *  System.out 은 콘솔 출력입니다.
         */

        // 키보드에서 값을 읽어 보자.
        try (InputStreamReader reader = new InputStreamReader(System.in)) {
            PrintWriter writer = new PrintWriter(System.out, true);
            System.out.println("텍스트를 입력하세요 (종료는 Ctrl + D)");
            System.out.println("---------------------------------");
            int charCode;
            while ((charCode = reader.read())  != -1) {
                writer.print((char) charCode);
            }
            writer.flush(); // 버퍼 남은 데이터를 즉시 출력
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    } // end of main

}

-키보드 입력을 파일에 저장하는 코드

package io.ch16;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStreamReader;

public class FileStreamUserInput {

    public static void main(String[] args) {
        writeUserInputToFile("user_input.txt");
    }

    public static void writeUserInputToFile(String fileName) {
        /**
         * 키보드 입력 -> InputStreamReader(System.in) (바이트 -> 문자 변환)
         * 파일에 쓰기 -> FileWriter(fileName)         (문자 기반 파일 출력)
         */

        try (InputStreamReader reader = new InputStreamReader(System.in);
             FileWriter writer = new FileWriter(fileName, true)) {

            System.out.println("텍스트를 입력하세요(종료 :" + " Ctrl + D)");
            //1. 사용자가 입력한 값을 받자 - 키보드에서
            int charCode;
            while ((charCode = reader.read()) != -1) {
                //[]<--임시 메모리 공간 버퍼
                writer.write(charCode);
                //문자 하나 받을 때 마다 즉시 파일에 저장
            }
            System.out.println(fileName + "에 텍스트를 모두 작성함");

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    //직접 코드 작성해보기
    //파일에서 텍스트를 읽는 메서드를 직접 구형해 보세요
    public static void readFromFile(String fileName) {
        ///...파일에 내용을 문자 기반으로 읽어서 콘솔창에 출력

        try (FileReader fileReader = new FileReader(fileName)) {
            int data;

            while ((data = fileReader.read()) != -1) {
                System.out.print((char) data);
            }

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

FileInputStream vs FileReader 비교

FileInputStreamFileReader

읽기 단위 1바이트 1문자 (char)
한글 처리 깨질 수 있음 자동 처리
용도 이미지, 동영상, 바이너리 파일 텍스트 파일
String 직접 쓰기 불가 (getBytes() 필요) 가능 (FileWriter)

 

-핵심 요약

문자 기반 스트림 = 한글 깨짐 문제 해결

FileReader        → 파일에서 문자 단위로 읽기  (FileInputStream 의 문자 버전)
FileWriter        → 파일에 문자 단위로 쓰기   (FileOutputStream 의 문자 버전)
InputStreamReader → 바이트 스트림 → 문자 스트림 변환 브릿지
                    System.in(표준 입력 스트림)을 문자로 읽을 때 사용

텍스트 파일 (한글 포함)  → FileReader / FileWriter
이미지, 동영상, zip 등   → FileInputStream / FileOutputStream