12

メモ帳に保存したテキスト ファイルを java.util.Scanner で読み取る際に問題が発生しましたが、他のファイルでは問題なく動作します。基本的に、問題のファイルを読み込もうとすると、完全に手ぶらで表示されます -- hasNextLine() が false である、バッファが空であるなどです。は、ファイル内の任意の場所で中引用符です。例外はスローされません。同じファイルの BufferedReader には問題がないことに注意してください。

try {        
    int count = 0;
    Scanner scanner = new Scanner(new File("C:/myfile.txt"));

    while (scanner.hasNextLine()) {
        count++;
        scanner.nextLine();
    }

    scanner.close();
    System.out.print(count);

    count = 0;
    BufferedReader reader = new BufferedReader(new FileReader("C:/myfile.txt"));

    while (reader.readLine() != null) {
        count++;
    }

    reader.close();
    System.out.print(count);
}
catch(IOException e) {
    e.printStackTrace();
}

上記のコードは、単一のカーリー クォーテーションのみを含むファイルを読み取り、"01" を出力します。Googleで検索すると、これを試すようになりました:

Scanner scanner = new Scanner(new File("C:/myfile.txt"), "ISO-8859-1");

これで動作します (つまり、"11" が出力されます)。また、メモ帳を開いて名前を付けて保存すると、下部のデフォルトのエンコーディングが「ANSI」になっていることにも気付きました。これを「UTF-8」に変更してファイルを保存すると、スキャナー (エンコードなし) も機能します。スキャナーに「UTF-8」と指定すると、もちろん UTF-8 で保存した場合にのみ機能しますが、「ISO-8859-1」は「ANSI」として保存しても機能するようです。

したがって、ファイルのエンコーディングに関係があることはわかっていますが、問題は、ファイルのエンコーディングについて何も理解していないことです。「ISO-8859-1」が何を意味するかについての私の知識は非常に曖昧です。ファイルをどのように保存しても、なぜそれが機能するのですか? BufferedReader が関係なく動作するのはなぜですか?

編集:

以下のリンク/コメントは、私を正しい方向に導くのに本当に役立ちました! 私はそれを理解したと思います。

まず、メモ帳で:

  • 「ANSI」はCP1252
  • 「ユニコード」はUTF-16LE
  • 「UTF-8」は…まあ、UTF-8

16 進数では、カーリー アポストロフィは次のように表されます。

  • CP1252:92
  • UTF-16LE: 1920年
  • UTF-8: E2 80 99

Charset.defaultCharset() によると、私のシステムで Java が使用するデフォルトのエンコーディングは UTF-8 です。そのため、ファイルを UTF-8 で保存すると、スキャナーは何を期待すべきかを認識していました。ただし、ファイルを CP1252 で保存すると、その「92」に達すると、そのエンコーディングで文字を表現する有効な方法ではないため、チョークしました。ファイルにそのような文字が含まれていない限り、問題なく動作します。「hello world」の 16 進数は、たまたま CP1252 と UTF-8 の両方で同じであり、たまたま問題が発生することはありません。

UTF-8 は UTF-16 ファイルでは機能しません。これは、ファイル内の文字に関係なく、バイト オーダー マーク ("FFFE") をどう処理するかがわからないためです。

一方、スキャナーを CP1252 または ISO-8859-1 に設定すると、はるかに寛容になります。必ずしも文字を正しく解釈するとは限りませんが、ファイル内の行を認識してループすることを妨げるものは何もありません。

Scanner に問題があるのに FileReader/BufferedReader に問題がない理由については、スキャナがファイルをトークン化する必要があるためだと思います。空白やその他のパタ​​ーンを識別できるように文字を解釈し、認識できないものがあるとチョークします。読者はその必要はありません。識別する必要があるのは改行だけです。

4

3 に答える 3

2

ScannerhasNextLineメソッドは、入力ファイルでエンコード エラーが発生した場合に false を返します。例外なく。これはイライラすることであり、JDK 8 のドキュメントでさえ、どこにも文書化されていません。

ファイルを 1 行ずつ読みたい場合は、代わりに次のようにします。

final BufferedReader input = new BufferedReader(new InputStreamReader(new FileInputStream("inputfile.txt"), "inputencoding"));

while (true) {
    String line = input.readLine();
    if (line == null) break;
    // process line
}

input.close();

inputencoding上記がファイルの正しいエンコーディングに置き換えられていることを確認してください。ほとんどの場合、utf-8またはasciiです。エンコーディングが一致しない場合でも、 のように途中で終了することはありませんScanner

于 2014-04-09T05:38:43.873 に答える