CodeGym /행동 /JAVA 25 SELF /파일 재인코딩: 한 인코딩으로 읽고 다른 인코딩으로 쓰기

파일 재인코딩: 한 인코딩으로 읽고 다른 인코딩으로 쓰기

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

1. 소개

회계 담당자로부터 "Windows-1251"로 저장된 보고서 파일을 받았다고 가정해 봅시다(키릴 문자용의 오래된 인코딩). 여러분의 Java 애플리케이션은 모든 입력 데이터를 "UTF-8"로 기대하기 때문에 그렇지 않으면 오류가 나거나 글자가 깨져 보일 수 있습니다. 혹은 "ISO-8859-1"만 받는 시스템과 연동해야 할 수도 있죠. 어떻게 할까요? 물론, 파일을 재인코딩해야 합니다!

재인코딩은 한 인코딩으로 저장된 파일에서 텍스트를 읽어 다른 인코딩으로 저장하는 과정입니다. 마치 받은 사람이 정확히 이해할 수 있도록 편지를 다른 언어로 옮겨 적는 것과 같습니다.

Java에서 재인코딩이 동작하는 방식: 일반적인 접근

Java에서 문자열(String)은 프로그램 내부에서 항상 Unicode(UTF‑16)로 저장됩니다. 즉, 파일에서 텍스트를 읽어 들이면 이미 “범용” 형태가 되므로 지원되는 어떤 인코딩으로든 다시 기록할 수 있습니다. 따라서 재인코딩은 간단합니다:

  • 올바른 원본 인코딩을 지정해 파일을 문자열로 읽습니다.
  • 그 문자열을 새 파일로 쓸 때 원하는 대상 인코딩을 명시합니다.

개념도:

[인코딩 A의 파일] --(Charset A로 읽기)--> [메모리의 String] --(Charset B로 쓰기)--> [인코딩 B의 파일]

2. 재인코딩 단계별 알고리즘

1단계. 원본 인코딩과 대상 인코딩 결정
원본 인코딩은 원본 파일이 저장된 인코딩입니다(예: "Windows-1251"). 대상 인코딩은 결과를 얻고자 하는 인코딩입니다(예: "UTF-8").

2단계. 해당 인코딩으로 읽기 스트림 열기
Files.newBufferedReader(Path, Charset) 또는 고전적인 InputStreamReader를 사용합니다.

3단계. 해당 인코딩으로 쓰기 스트림 열기
Files.newBufferedWriter(Path, Charset) 또는 고전적인 OutputStreamWriter를 사용합니다.

4단계. 줄을 읽어 새 파일에 쓰기
줄 단위로 읽고(파일이 작다면 전체를 읽어도 됨), 각 줄을 새 파일에 기록합니다.

5단계. 스트림 닫기(try-with-resources 사용 권장)
이렇게 하면 리소스를 올바르게 해제할 수 있습니다. try-with-resources 구문을 사용하세요.

3. 코드 예시: 재인코딩 Windows-1251 → UTF-8

Windows‑1251에서 UTF‑8로 파일을 재인코딩하는 간단한 프로그램을 구현해 봅시다. 특히 러시아어 데이터와 작업할 때 현실에서 자주 마주치는 사례입니다.

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

public class FileReencoder {
    public static void main(String[] args) throws IOException {
        // 파일 경로
        Path inputPath = Paths.get("input-1251.txt");
        Path outputPath = Paths.get("output-utf8.txt");

        // 원본 인코딩 Windows-1251로 reader 열기
        try (
            BufferedReader reader = Files.newBufferedReader(inputPath, Charset.forName("Windows-1251"));
            BufferedWriter writer = Files.newBufferedWriter(outputPath, StandardCharsets.UTF_8)
        ) {
            String line;
            while ((line = reader.readLine()) != null) {
                writer.write(line);
                writer.newLine(); // 줄바꿈을 잊지 마세요!
            }
        }

        System.out.println("파일이 Windows-1251에서 UTF-8로 성공적으로 재인코딩되었습니다!");
    }
}

여기서는 읽기용 인코딩(Charset.forName("Windows-1251"))과 쓰기용 인코딩(StandardCharsets.UTF_8)을 명시적으로 지정합니다. 그런 다음 try-with-resources를 사용해 오류가 발생해도 스트림이 자동으로 닫히도록 합니다. writer.newLine()은 줄바꿈을 추가해 파일의 구조를 보존합니다.

4. 중요한 포인트와 팁

파일의 원본 인코딩은 어떻게 알 수 있나요?

  • 파일 자체에는 인코딩을 나타내는 “라벨”이 없습니다(예외는 BOM이지만 항상 있는 것은 아님).
  • 파일을 여러분이 만들었다면 저장할 때 사용했던 같은 인코딩을 사용하세요.
  • 어디선가 받은 파일이라면 인코딩을 보여주는 에디터(예: Notepad++, Visual Studio Code)로 열어 보세요.
  • Linux에서는 file -i file_name 명령을 사용할 수 있지만, 항상 정확하게 인코딩을 판별하지는 않습니다.

잘못된 원본 인코딩을 지정하면 어떻게 되나요?

글자가 깨지거나 일부 문자가 손실됩니다. 예를 들어 Windows‑1251로 저장된 파일을 UTF‑8로 읽으면 러시아어 문자가 "Привет"처럼 보이는 깨진 문자열로 변할 수 있습니다.

예외 처리

파일 작업에서는 항상 오류가 발생할 수 있습니다: 파일을 찾을 수 없음, 권한 부족, 잘못된 인코딩 등. 예외를 처리(try-catch)하거나 상위로 던지기(throws)를 사용해 애플리케이션이 “이유도 모른 채” 중단되지 않도록 하세요.

대용량 파일 작업

파일이 매우 큰 경우(기가바이트 단위)에는 예시처럼 줄 단위로 읽고 쓰세요. 파일 전체를 한 번에 메모리로 읽지 마세요 — OutOfMemoryError가 발생할 수 있습니다.

실시간(스트리밍) 재인코딩

파일이 아주 크다면 중간 파일을 만들지 않고도 “실시간”으로 처리할 수 있습니다 — 예를 들어 네트워크에서 들어오는 데이터를 스트리밍 처리할 때 그렇게 할 수 있습니다.

5. 파일 재인코딩에서 흔한 실수

오류 №1: 잘못된 원본 인코딩. 원본 인코딩을 잘못 지정하면 결과가 좋지 않습니다: 러시아어 “안녕”에 해당하는 단어가 "Привет"처럼 보일 수 있습니다. 파일이 어떤 인코딩으로 생성되었는지 항상 확인하세요.

오류 №2: 시스템 기본 인코딩의 암묵적 사용. 인코딩을 명시하지 않으면 Java는 시스템 기본값(System.getProperty("file.encoding"))을 사용합니다. 이로 인해 컴퓨터마다 결과가 달라질 수 있습니다(예: Windows — cp1251, Linux — UTF‑8).

오류 №3: 파일 전체를 메모리로 읽고 쓰기. 대용량 파일에 이런 접근을 하면 메모리가 고갈됩니다. 줄 단위로 읽고 쓰세요.

오류 №4: 처리되지 않은 예외. 파일이 존재하지 않거나 다른 프로세스가 사용 중이거나 손상된 문자가 포함될 수 있습니다. 항상 예외를 처리하거나 try-with-resources를 사용하세요.

오류 №5: 바이너리 파일 재인코딩. 이미지, PDF, 아카이브 등 바이너리 파일을 재인코딩하려고 하지 마세요! 파일이 손상됩니다. 재인코딩은 텍스트 파일에만 의미가 있습니다.

1
과제
JAVA 25 SELF, 레벨 37, 레슨 4
잠금
디지털 기록관리자: 오래된 문서를 새 형식으로 마이그레이션 🏛️
디지털 기록관리자: 오래된 문서를 새 형식으로 마이그레이션 🏛️
1
과제
JAVA 25 SELF, 레벨 37, 레슨 4
잠금
디지털 데이터 구조대원: 장애로부터 안전한 재인코딩 🚨
디지털 데이터 구조대원: 장애로부터 안전한 재인코딩 🚨
1
설문조사/퀴즈
인코딩 작업, 레벨 37, 레슨 4
사용 불가능
인코딩 작업
인코딩 작업
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION