Java FileReaderエンコーディングの問題


130

java.io.FileReaderを使用していくつかのテキストファイルを読み取って文字列に変換しようとしましたが、結果が正しくエンコードされておらず、まったく読み取れません。

これが私の環境です:

  • Windows 2003、OSエンコーディング:CP1252

  • Java 5.0

私のファイルはUTF-8エンコードまたはCP1252エンコードされており、一部のファイル(UTF-8エンコードファイル)には中国語(非ラテン)文字が含まれている場合があります。

次のコードを使用して作業を行います。

   private static String readFileAsString(String filePath)
    throws java.io.IOException{
        StringBuffer fileData = new StringBuffer(1000);
        FileReader reader = new FileReader(filePath);
        //System.out.println(reader.getEncoding());
        BufferedReader reader = new BufferedReader(reader);
        char[] buf = new char[1024];
        int numRead=0;
        while((numRead=reader.read(buf)) != -1){
            String readData = String.valueOf(buf, 0, numRead);
            fileData.append(readData);
            buf = new char[1024];
        }
        reader.close();
        return fileData.toString();
    }

上記のコードは機能しません。テキストがUTF-8でエンコードされていても、FileReaderのエンコードはCP1252であることがわかりました。しかし、java.io.FileReaderのJavaDocは次のように述べています。

このクラスのコンストラクタは、デフォルトの文字エンコーディングとデフォルトのバイトバッファサイズが適切であることを前提としています。

これは、FileReaderを使用している場合、自分で文字エンコーディングを設定する必要がないことを意味しますか?しかし、私は現在誤ってエンコードされたデータを取得しました、私の状況に対処する正しい方法は何ですか?ありがとう。


ループ内でString.valueOf()を緩めて、StringBuffer.append(char []、int、int)を直接使用する必要もあります。これにより、char []のコピーを大幅に節約できます。また、StringBufferをStringBuilderに置き換えます。これはあなたの質問に関するものではありません。
ヨアヒムザウアー

1
私はそれを言うのが嫌いですが、貼り付けた部分の直後にJavaDocを読みましたか?「これらの値を自分で指定するには、FileInputStreamにInputStreamReaderを作成します」と書かれている部分はわかりますか?
Powerlord 2009年

コメントのおかげで、実際にはJavaDocを読みましたが、これらの値を自分で指定して「FileInputStreamでInputStreamReaderを構築する」に切り替える必要があるかどうかはわかりません。
nybon 2009年

はい、ファイルがプラットフォームのデフォルトのエンコーディング以外のものであることがわかっている場合は、どちらを使用するかをInputStreamReaderに通知する必要があります。
アランムーア

回答:


248

はい、読み取るファイルのエンコーディングを指定する必要があります

はい。これは、読み取るファイルのエンコーディングを知っている必要があることを意味します。

いいえ、特定の「プレーンテキスト」ファイルのエンコーディングを推測する一般的な方法はありません。

の引数が1つのコンストラクタは、FileReader常にプラットフォームのデフォルトのエンコーディングを使用しますがこれは一般に悪い考えです。

Java 11以降FileReaderは、エンコーディングを受け入れるコンストラクタも取得new FileReader(file, charset)していnew FileReader(fileName, charset)ます。

以前のバージョンのJavaでは、を使用する必要があります。new InputStreamReader(new FileInputStream(pathToFile), <encoding>)


1
InputStream is = new FileInputStream(filename); ここでは、ロシア語のファイル名でエラーファイルが見つからないというエラーが発生しました
Bhanu Sharma

3
InputStreamReaderの使用を提案するための+1。ただし、コードブロックでリンクを使用すると、コードをコピーして貼り付けることが難しくなります。これを変更できる場合、thx
Ferrybig

1
エンコーディングは「UTF-8」か「UTF8」か。よるとエンコーディングでJava SE参照するので、InputStreamReaderあるjava.ioクラスが、それは「UTF8」でしょうか?
NobleUplift 2015年

9
@NobleUplift:最も安全な賭けはですがStandardCharsets.UTF_8、そこにタイプミスする可能性はありません;-)はい、文字列で行けば"UTF8"正しいでしょう(両方の方法を受け入れることを覚えているようですが)。
Joachim Sauer

1
@JoachimSauer実際、これは。の目的の1つByte Order Markです。:)、このような私はJavaのFileReaderのは、自動的にUTF-16などBOMを持って検出することができないことをそれが奇妙見つけると...実際、私は一度書いたUnicodeFileReader正確ことないことを。残念ながらクローズドソースですが、Google には非常によく似たUnicodeReaderがあります。
Stijn de Witt

79

FileReader は、Javaのプラットフォームのデフォルトのエンコーディングを使用します。これは、Javaを実行しているコンピュータのシステム設定に依存し、通常、そのロケールのユーザーの間で最も人気のあるエンコーディングです。

この「最良の推測」が正しくない場合は、エンコードを明示的に指定する必要があります。残念ながら、FileReaderこれは許可されていません(APIの主な見落とし)。代わりに、new InputStreamReader(new FileInputStream(filePath), encoding)ファイルに関するメタデータを使用し、理想的にはエンコーディングを取得する必要があります。


24
「APIの主な見落とし」-この説明に感謝-私が求めていたコンストラクタが見つからないのはなぜだろうと思っていました。乾杯ジョン
-monojohnny

@Bhanu Sharma:それは異なるレベルでのエンコードの問題です。ファイル名の取得元を確認し、コンパイラーが使用するエンコードがハードコーディングされているかどうかを確認してください。
Michael Borgwardt 2014

1
@BhanuSharma:ファイル名のエンコードの問題は、この質問とは関係ありません。多くの既存の「Unicodeファイル名がJavaで機能しない理由」の質問の1つを参照してください。Spoiler:FileReaderのようなjava.io APIは、WindowsでUnicodeをサポートできないC標準ライブラリファイルシステムコールを使用します。代わりにjava.nioの使用を検討してください。
ボビンス2015年

1
FileReaderJavaのプラットフォームのデフォルトのエンコーディングを使用します。これは、Javaを実行しているコンピューターのシステム設定に依存し、通常、そのロケールでユーザーの間で最も人気のあるエンコーディングです。」そうは思いません。少なくともWindows。奇妙な技術的または歴史的な理由により、JVMはUnicodeがWindowsで「すべての新しいアプリケーション」に推奨されるエンコーディングであるという事実を無視し、代わりに常にレガシーアプリのフォールバックとして構成さたレガシーエンコーディングが「プラットフォームのデフォルト」であるかのように動作します。
Stijn de Witt

6
Javaアプリがファイル/ストリーム/リソースの読み取りまたは書き込みのたびにエンコードを明示的に指定しないと、信頼性のある動作ができないため、壊れてしまうと私は言いさえします。
Stijn de Witt


6

Java 7以降のドキュメントの場合、これを使用できます。

BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8);

ここにすべてのCharsets ドキュメントがあります

たとえば、ファイルがCP1252にある場合、この方法を使用します

Charset.forName("windows-1252");

これは、IOとNIOの両方のドキュメントの Javaエンコーディングの他の正規名です

ファイルで取得したエンコーディングが正確にわからない場合は、Googleが提供するこのツールのようなサードパーティ製のライブラリを使用できます。


1

InputStreamReaderを使用するFileInputStreamは、直接FileReaderを使用するよりも優れています。後者では、エンコーディング文字セットを指定できないためです。

次に、BufferedReader、FileInputStream、およびInputStreamReaderを一緒に使用して、ファイルから行を読み取る例を示します。

List<String> words = new ArrayList<>();
List<String> meanings = new ArrayList<>();
public void readAll( ) throws IOException{
    String fileName = "College_Grade4.txt";
    String charset = "UTF-8";
    BufferedReader reader = new BufferedReader(
        new InputStreamReader(
            new FileInputStream(fileName), charset)); 

    String line; 
    while ((line = reader.readLine()) != null) { 
        line = line.trim();
        if( line.length() == 0 ) continue;
        int idx = line.indexOf("\t");
        words.add( line.substring(0, idx ));
        meanings.add( line.substring(idx+1));
    } 
    reader.close();
}

0

別のラテン語として、例えばキリル文字の場合、次のようなものを使用できます。

FileReader fr = new FileReader("src/text.txt", StandardCharsets.UTF_8);

また、.txtファイルがUTF-8(デフォルトではないANSI)形式で保存されていることを確認してください。乾杯!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.