CodeGym /행동 /JAVA 25 SELF /파일 읽기/쓰기 시 인코딩 지정

파일 읽기/쓰기 시 인코딩 지정

JAVA 25 SELF
레벨 37 , 레슨 2
사용 가능

1. 소개

솔직히 말해, 러시아어 텍스트 대신 Привет 같은 이상한 문자를 본 적이 있다면 이미 잘못된 인코딩의 피해자입니다. 이는 파일을 한 인코딩으로 저장해 놓고 다른 인코딩으로 읽을 때 발생합니다. 예를 들어 파일은 UTF-8로 저장되었는데 Windows-1251로 읽거나 그 반대인 경우입니다.

Java는 기본적으로 시스템 인코딩을 사용하며, 다음과 같이 확인할 수 있습니다:

System.out.println(System.getProperty("file.encoding"));

어떤 컴퓨터에서는 UTF-8, 다른 곳에서는 Windows-1251, 또 어떤 곳에서는 ISO-8859-1일 수 있습니다. 따라서 인코딩은 항상 명시적으로 지정하는 것이 가장 좋습니다. 이는 다국어 데이터를 다루거나, 파일이 여러 컴퓨터에서 사용되거나 다른 프로그램에서 열릴 수 있거나, 코드가 당신의 컴퓨터뿐 아니라 어떤 환경에서도 동일하게 동작하길 원할 때 특히 중요합니다.

Charset 클래스: 인코딩 세계의 친구

Java에서 인코딩 작업에는 java.nio.charset.Charset 클래스를 사용합니다. 이 클래스는 인코딩을 이름(예: "UTF-8")으로 지정할 수도 있고 표준 상수(StandardCharsets.UTF_8)를 사용할 수도 있게 해 줍니다.

표준 인코딩 예:

인코딩 Java 상수
UTF-8
StandardCharsets.UTF_8
UTF-16
StandardCharsets.UTF_16
ISO-8859-1
StandardCharsets.ISO_8859_1
Windows-1251
Charset.forName("Windows-1251")

상수를 사용하는 편이 더 좋습니다. 이름을 잘못 쓸 가능성이 줄어들고 UnsupportedCharsetException이 발생하지 않습니다.

2. 인코딩을 지정하여 파일 읽기

예전 방식:

import java.io.*;
import java.nio.charset.StandardCharsets;

BufferedReader reader = new BufferedReader(
    new InputStreamReader(
        new FileInputStream("example.txt"),
        StandardCharsets.UTF_8 // <-- 인코딩을 명시적으로 지정
    )
);

현대적인 방식:

import java.nio.file.*;
import java.nio.charset.StandardCharsets;
import java.io.BufferedReader;

BufferedReader reader = Files.newBufferedReader(
    Paths.get("example.txt"),
    StandardCharsets.UTF_8 // <-- 인코딩을 명시적으로 지정
);

둘째 방법 사용을 권장합니다 — 더 짧고 더 안전하며 try-with-resources와 잘 어울립니다.

예: 파일에서 한 줄 읽기

try (BufferedReader reader = Files.newBufferedReader(
        Paths.get("hello.txt"),
        StandardCharsets.UTF_8)) {
    String line = reader.readLine();
    System.out.println("읽었습니다: " + line);
}

왜 중요한가: 파일이 UTF-8로 저장되어 있는데 Windows-1251로 읽으면 키릴 문자 등이 깨집니다. 올바른 인코딩을 지정하면 어떤 OS에서도 텍스트를 제대로 읽을 수 있습니다.

3. 인코딩을 지정하여 파일 쓰기

예전 방식:

import java.io.*;
import java.nio.charset.StandardCharsets;

BufferedWriter writer = new BufferedWriter(
    new OutputStreamWriter(
        new FileOutputStream("example.txt"),
        StandardCharsets.UTF_8 // <-- 인코딩을 명시적으로 지정
    )
);

현대적인 방식:

import java.nio.file.*;
import java.nio.charset.StandardCharsets;
import java.io.BufferedWriter;

BufferedWriter writer = Files.newBufferedWriter(
    Paths.get("example.txt"),
    StandardCharsets.UTF_8 // <-- 인코딩을 명시적으로 지정
);

예: 파일에 한 줄 쓰기

try (BufferedWriter writer = Files.newBufferedWriter(
        Paths.get("hello.txt"),
        StandardCharsets.UTF_8)) {
    writer.write("안녕, 세상!");
}

결과: 파일은 UTF-8로 저장되며, UTF-8을 지원하는 어떤 편집기에서도 올바르게 열 수 있습니다.

4. 유용한 팁과 확인 사항

지원되는 인코딩 확인 방법

import java.nio.charset.Charset;

public class ListCharsets {
    public static void main(String[] args) {
        System.out.println("사용 가능한 인코딩:");
        Charset.availableCharsets().forEach((name, charset) -> System.out.println(name));
    }
}

팁: 아주 특수한 인코딩(예: 고대 한자나 이모지에 특화된 인코딩 등)을 사용한다면, 해당 인코딩이 JVM에서 지원되는지 확인하세요.

try-with-resources 사용: 스트림 닫는 것 잊지 않기

파일을 다룰 때는 리소스 누수를 막기 위해 스트림을 반드시 닫아야 합니다. 최신 Java 코드는 try-with-resources 구문을 사용합니다:

try (BufferedReader reader = Files.newBufferedReader(path, charset)) {
    // 파일을 처리합니다
}

예외가 발생하더라도 스트림은 자동으로 닫힙니다.

권장 사항

  • 항상 인코딩을 명시적으로 지정하세요. 기본값으로도 동작한다는 확신이 있더라도 읽기/쓰기 시 인코딩을 지정하는 편이 안전합니다.
  • 새로운 파일에는 UTF-8을 사용하세요 — 사실상의 표준이며, 웹, JSON, XML 작업이나 파일이 어디서나 읽히길 원할 때 특히 좋습니다.
  • 기존 파일(예: 1C 내보내기, 오래된 데이터베이스, Windows에서 만든 CSV)에는 해당 파일이 저장된 인코딩을 사용하세요(예: Windows-1251, ISO-8859-1).
  • 인코딩을 명시할 수 없는 구식 클래스는 사용하지 마세요: FileReader/FileWriter. 대신 InputStreamReader/OutputStreamWriter에 인코딩을 명시하거나 Files의 메서드를 사용하세요.
  • 큰 파일에는 버퍼링(BufferedReader/BufferedWriter)을 사용하여 메모리 사용을 줄이세요.

5. 인코딩 작업 시 흔한 오류

오류 №1: 파일 읽기/쓰기 시 인코딩을 지정하지 않음.
인코딩을 지정하지 않으면 Java는 시스템 기본값("file.encoding")을 사용합니다. 내 컴퓨터에서는 잘 보이지만 동료의 컴퓨터에서는 “깨진 문자”가 나타날 수 있습니다.

오류 №2: 읽기와 쓰기에 사용하는 인코딩이 일치하지 않음.
파일을 한 인코딩으로 저장해 놓고 다른 인코딩으로 읽는 경우입니다. 예를 들어 파일은 UTF-8로 저장했는데 Windows-1251로 읽으면 키릴 문자가 깨집니다.

오류 №3: 구식 클래스 FileReader/FileWriter 사용.
이 클래스들은 인코딩을 명시적으로 지정할 수 없으므로 사용을 권장하지 않습니다. 대신 InputStreamReader/OutputStreamWriter에 인코딩을 지정하거나 Files의 메서드를 사용하세요.

오류 №4: 인코딩 이름 오기.
예를 들어 "utf8" 대신 "UTF-8", "win1251" 대신 "Windows-1251"처럼 잘못 쓰는 경우입니다. Java는 UnsupportedCharsetException을 던집니다.

오류 №5: 스트림을 닫지 않음 — 파일이 제대로 기록되지 않음.
try-with-resources를 사용하지 않거나 스트림을 명시적으로 닫지 않으면 일부 데이터가 디스크에 쓰이지 않을 수 있습니다.

코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION