Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/328.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
卷曲的引号导致Java Scanner hasNextLine()为false——为什么?_Java_Encoding_Utf 8 - Fatal编程技术网

卷曲的引号导致Java Scanner hasNextLine()为false——为什么?

卷曲的引号导致Java Scanner hasNextLine()为false——为什么?,java,encoding,utf-8,Java,Encoding,Utf 8,我在让java.util.Scanner读取我保存在记事本中的文本文件时遇到了一个问题,尽管它可以与其他人一起正常工作。基本上,当它试图读取问题文件时,它会空手而归——hasNextLine()为false,buffer为空,等等。我把它的范围缩小到这样一个事实,即如果文件中任何地方有卷曲的引号,它甚至不会读取第一行。没有抛出异常。请注意,同一文件上的BufferedReader没有问题 try { int count = 0; Scanner scanner =

我在让java.util.Scanner读取我保存在记事本中的文本文件时遇到了一个问题,尽管它可以与其他人一起正常工作。基本上,当它试图读取问题文件时,它会空手而归——hasNextLine()为false,buffer为空,等等。我把它的范围缩小到这样一个事实,即如果文件中任何地方有卷曲的引号,它甚至不会读取第一行。没有抛出异常。请注意,同一文件上的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”。谷歌上的搜索让我尝试了以下方法:

Scanner scanner = new Scanner(new File("C:/myfile.txt"), "ISO-8859-1");
org.mozilla.universalchardet.UniversalDetector
这使它工作(即,它打印出“11”)。我还注意到,如果我进入记事本并执行另存为。。。底部的默认编码是“ANSI”。如果我将其更改为“UTF-8”并保存文件,那么扫描仪(无编码)也可以工作。如果我告诉扫描器“UTF-8”,那么可以理解的是,只有当我保存为UTF-8时,它才能工作,但是即使我将它保存为“ANSI”时,“ISO-8859-1”似乎也能工作

所以,我知道这与文件编码有关,但问题是我对文件编码一无所知。我对“ISO-8859-1”的理解非常模糊;为什么无论我如何保存文件,它都能工作?为什么BufferedReader可以正常工作

编辑:

下面的链接/评论真的帮我指明了正确的方向!我想我已经弄明白了

首先,在记事本中:

  • “ANSI”是CP1252
  • “Unicode”是UTF-16LE
  • “UTF-8”是。。。嗯,UTF-8
十六进制中,卷曲撇号表示为:

  • CP1252:92
  • UTF-16LE:1920
  • UTF-8:E28099
根据Charset.defaultCharset(),Java在我的系统上使用的默认编码是UTF-8。所以当我用UTF-8保存文件时,扫描仪知道会发生什么。然而,当我将文件保存在CP1252中时,当它遇到“92”时,它就阻塞了,因为它不是用这种编码表示字符的有效方法。只要文件中没有任何这样的字符,“hello world”的十六进制在CP1252和UTF-8中都是相同的,不会引起问题,它就可以正常工作

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();
}
UTF-8不适用于UTF-16文件,因为它不知道如何处理字节顺序标记(“FFFE”),无论文件中包含哪些字符

另一方面,当我将扫描仪设置为CP1252或ISO-8859-1时,它的容忍度要高得多。请注意,它不一定能正确解释字符,但没有任何东西可以阻止它识别文件中的行并循环


至于为什么扫描器有问题,而FileReader/BufferedReader没有,我猜这是因为扫描器需要标记文件,即解释字符以便它能够识别空白和其他模式,因此当出现无法识别的内容时,它会阻塞。读者不需要这样做。它需要识别的只是换行符。

如果在创建扫描仪时未指定编码,它将尝试根据字节顺序标记(BOM)来判断编码,BOM是文件的前几个字节。如果没有,它将默认为操作系统使用的任何默认值。由于您使用的是Windows,因此默认值为cp-1252。似乎记事本正在使用ISO-8859-1保存您的文本文件,ISO-8859-1与cp-1252类似,但不同。有关更多详细信息,请参阅此链接:

当您将其另存为UTF-8时,它可能会将UTF-8 BOM表放在文件的开头,扫描仪可以在其上拾取


如果你想更深入地了解BOM表,可以在维基百科上查找——这篇文章非常好。您还可以下载PSPad并以十六进制模式打开文本文件以查看各个字节。希望有帮助:)

不久前,我在用户编辑的配置文件中遇到了类似的问题。因为我不知道用户将使用哪种类型的编辑器,所以我尝试以下方法:

Scanner scanner = new Scanner(new File("C:/myfile.txt"), "ISO-8859-1");
org.mozilla.universalchardet.UniversalDetector
可从此处获取:

https://code.google.com/p/juniversalchardet/

检测字符编码不是一件简单的事情,所以我不能确定这个库在任何情况下都能工作,但对我来说已经足够了。看一看,也许会有助于检测您的编码,然后将其设置为
Scanner

Scanner
,如果在输入文件中遇到编码错误,hasNextLine方法只会返回false。毫无例外。这是令人沮丧的,它没有记录在任何地方,甚至在任何地方

如果您只想逐行读取文件,请使用以下选项:

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

一样提前终止,这是一篇很好的文章,可以帮助您在访问过程中获得帮助。如果您将
字符串
(不是
文件
)传递给
扫描仪,它是否也会被卷曲括号卡住?如果我在代码中创建一个带有卷曲引号的字符串(“”),是的,它似乎起作用了。花括号没有问题。这不是很好,但它确实让我走上了正确的道路,PSPad也很有帮助。我用我能理解的东西编辑了我的问题。谢谢