Mys*_*per 12 java encoding utf-8
我一直遇到一个问题,让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();
}
Run Code Online (Sandbox Code Playgroud)
上面的代码,读取一个只包含单个卷曲引号的文件,打印出"01".搜索谷歌让我试试这个:
Scanner scanner = new Scanner(new File("C:/myfile.txt"), "ISO-8859-1");
Run Code Online (Sandbox Code Playgroud)
这使它工作(即它打印出"11").我还注意到,如果我进入记事本并执行另存为...底部的默认编码是"ANSI".如果我将其更改为"UTF-8"并保存文件,则扫描仪(没有编码)也可以.如果我告诉扫描仪"UTF-8",那么可以理解的是,只有当我保存为UTF-8时它才有效,但是"ISO-8859-1"似乎使其工作,即使我将其保存为"ANSI".
所以,我知道它与文件编码有关,但问题是我对文件编码一无所知.我对"ISO-8859-1"的含义非常模糊; 无论我如何保存文件,为什么它会使它工作?为什么BufferedReader无论如何都能正常工作?
编辑:
下面的链接/评论确实帮助我指明了正确的方向!我想我已经明白了.
首先,在记事本中:
在十六进制中,卷曲撇号表示为:
根据Charset.defaultCharset(),我在我的系统上使用的默认编码是UTF-8.因此,当我以UTF-8保存文件时,扫描仪知道会发生什么.但是,当我在CP1252中保存文件时,它一旦达到"92"就会被阻塞,因为它不是表示该编码中字符的有效方式.只要文件中没有任何这样的字符,它就可以正常工作 - "hello world"的十六进制在CP1252和UTF-8中都是相同的,并且不会导致问题.
UTF-8不能与UTF-16文件一起使用,因为它不知道如何处理字节顺序标记("FFFE"),无论文件中有什么字符.
另一方面,当我将扫描仪设置为CP1252或ISO-8859-1时,它更宽容.注意,它并不一定正确地解释字符,但没有什么可以阻止它识别文件中的行并循环.
至于为什么Scanner有问题但FileReader/BufferedReader没有问题,我猜这是因为扫描仪需要对文件进行标记,即.解释字符,以便它可以识别空白和其他模式,所以当有无法识别的东西时它会窒息.读者不需要这样做.所有它需要识别的是换行符.
如果您在创建扫描器时没有指定编码,它会尝试根据字节顺序标记 (BOM) 来确定编码,它是文件的前几个字节。如果它没有,它将默认为操作系统使用的任何默认值。由于您使用的是 Windows,因此默认值为 cp-1252。记事本似乎正在使用 ISO-8859-1 保存您的文本文件,它与 cp-1252 类似,但不一样。有关更多详细信息,请参阅此链接:
http://www.i18nqa.com/debug/table-iso8859-1-vs-windows-1252.html
当您将其另存为 UTF-8 时,它可能会将 UTF-8 BOM 放在文件的开头,并且扫描仪可以读取它。
如果您想更多地了解 BOM,请在维基百科中查找——这篇文章非常好。您还可以下载 PSPad 并以十六进制模式打开文本文件以查看各个字节。希望有帮助:)
| 归档时间: |
|
| 查看次数: |
2601 次 |
| 最近记录: |