7

iso-8859-1 としてエンコードされ、ô などの文字を含むファイルがあります。

次のようなJavaコードでこのファイルを読んでいます:

File in = new File("myfile.csv");
InputStream fr = new FileInputStream(in);
byte[] buffer = new byte[4096];
while (true) {
    int byteCount = fr.read(buffer, 0, buffer.length);
    if (byteCount <= 0) {
        break;
    }

    String s = new String(buffer, 0, byteCount,"ISO-8859-1");
    System.out.println(s);
}

ただし、ô 文字は常に文字化けし、通常は ? として出力されます。.

私はこの件について読みました(そして途中で少し学びました)。

しかし、まだこれを機能させることはできません

興味深いことに、これはローカル PC (xp) では機能しますが、Linux ボックスでは機能しません。

次を使用して、jdkが必要な文字セットをサポートしていることを確認しました(これらは標準であるため、これは驚くことではありません)。

System.out.println(java.nio.charset.Charset.availableCharsets());
4

5 に答える 5

15

ファイルが実際には ISO-8859-1 としてエンコードされていないか、System.out が文字を出力する方法を認識していない可能性があります。

最初に確認するには、ファイル内の関連するバイトを調べることをお勧めします。2番目を確認するには、文字列内の関連する文字を調べて、次のように出力します

 System.out.println((int) s.getCharAt(index));

どちらの場合も、結果10 進数で 244 になります。0xf4 16 進数。

一般的なアドバイスについては、Unicode デバッグに関する私の記事を参照してください(提示されたコードは C# ですが、Java に変換するのは簡単で、原則は同じです)。

ちなみに、一般的には、適切なエンコーディングでストリームをラップしますInputStreamReader。新しい文字列を「手動で」作成するよりも簡単です。ただし、これは単なるデモコードである可能性があります。

編集:コンソールが機能するかどうかを証明する非常に簡単な方法は次のとおりです。

 System.out.println("Here's the character: \u00f4");
于 2009-01-31T10:59:35.977 に答える
9

ファイルを固定サイズのバイト ブロックとして解析するのは適切ではありません --- 一部の文字のバイト表現が 2 つのブロックにまたがっている場合はどうなるでしょうか。InputStreamReader代わりに、適切な文字エンコーディングで を使用します。

 BufferedReader br = new BufferedReader(
         new InputStreamReader(
         new FileInputStream("myfile.csv"), "ISO-8859-1");

 char[] buffer = new char[4096]; // character (not byte) buffer 

 while (true)
 {
      int charCount = br.read(buffer, 0, buffer.length);

      if (charCount == -1) break; // reached end-of-stream 

      String s = String.valueOf(buffer, 0, charCount);
      // alternatively, we can append to a StringBuilder

      System.out.println(s);
 }

ところで、Unicode 文字が実際に正しく表示されることを確認してください。プログラムの出力をファイルにリダイレクトして、元のファイルと比較することもできます。

Jon Skeetが示唆するように、問題はコンソールに関連している可能性もあります。System.console().printf(s)違いがあるかどうか試してみてください。

于 2009-01-31T11:18:17.263 に答える
6

@Joel-あなた自身の答えは、問題がオペレーティングシステムのデフォルトのエンコーディング(UTF-8、Javaが取得したもの)と端末が使用しているエンコーディング(ISO-8859-1)の違いであることを確認しています。

このコードを考えてみましょう:

public static void main(String[] args) throws IOException {
    byte[] data = { (byte) 0xF4 };
    String decoded = new String(data, "ISO-8859-1");
    if (!"\u00f4".equals(decoded)) {
        throw new IllegalStateException();
    }

    // write default charset
    System.out.println(Charset.defaultCharset());

    // dump bytes to stdout
    System.out.write(data);

    // will encode to default charset when converting to bytes
    System.out.println(decoded);
}

デフォルトでは、私のUbuntu(8.04)端末はUTF-8エンコーディングを使用します。このエンコーディングでは、これが出力されます。

UTF-8
?ô

端末のエンコーディングをISO8859-1に切り替えると、次のように出力されます。

UTF-
8ôô

どちらの場合も、同じバイトがJavaプログラムによって発行されています。

5554 462d 380a f4c3 b40a

唯一の違いは、端末が受信したバイトを解釈する方法にあります。ISO 8859-1では、ôは0xF4としてエンコードされます。UTF-8では、ôは0xC3B4としてエンコードされます。他の文字は両方のエンコーディングに共通です。

于 2009-01-31T15:40:00.183 に答える
3

可能であれば、デバッガーでプログラムを実行して、作成後の「s」文字列の内容を確認してください。内容が正しい可能性がありますが、System.out.println(s) の呼び出し後に出力が文字化けします。その場合、Java が考える出力のエンコーディングと、Linux の端末/コンソールの文字エンコーディングとの間に不一致がある可能性があります。

于 2009-01-31T10:59:30.360 に答える
1

基本的に、ローカル XP PC では動作するが Linux では動作せず、まったく同じファイルを解析している場合 (つまり、ボックス間でバイナリ形式で転送した場合)、おそらく System.out に関係があります。 println 呼び出し。出力をどのように確認するかはわかりませんが、XP ボックスからリモート シェルに接続して確認する場合は、考慮すべきシェル (およびクライアント) の文字セットがあります。

さらに、Zach Scrivena が示唆していることも真実です。そのようにデータのチャンクから文字列を作成できるとは想定できません。InputStreamReader を使用するか、最初に完全なデータを配列に読み込みます (明らかに、大きなファイルでは機能しません)。 . ただし、XP で動作するように見えるので、この特定のケースでは、これはおそらく問題ではないと思います。

于 2009-01-31T11:36:55.057 に答える