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(元のエンコーディング)で開く
        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 名前_ファイル コマンドを使えますが、常に正確とは限りません。

元のエンコーディングを間違えるとどうなる?

文字化けや文字の欠落が発生します。たとえば、Windows‑1251 で保存されたファイルを UTF‑8 として読んでしまうと、キリル文字が "mojibake" に化けます。

例外処理

ファイル操作では常にエラーの可能性があります:ファイルが見つからない、権限がない、不正なエンコーディングなど。例外処理(try-catch)を行うか(throws で)上位に送出して、アプリが「理由もなく」落ちないようにしましょう。

大きなファイルの処理

ファイルが非常に大きい(ギガバイト級)場合は、ここで示したように行単位で読み書きしましょう。ファイル全体を一度にメモリへ読み込むのは避けないと、OutOfMemoryError になります。

オンザフライの再エンコード(ストリーミング)

ファイルがとても大きい場合、ネットワークからのデータをストリーミング処理しながら「オンザフライ」で読み書きし、中間ファイルを作らない方法も取れます。

5. 再エンコードでありがちなミス

誤り №1: 元エンコーディングの取り違え。 元のエンコーディングを誤ると結果は悲惨です。「Privet」が "Привет" に化けます。ファイルがどのエンコーディングで作成されたかを必ず確認しましょう。

誤り №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