尝试读取一个 500,000 行的大文件并将其存储在 java 中的数组中

Trying to read a big file of 500,000 lines and store it in an array in java

提问人:Maggie RIv 提问时间:3/13/2023 最后编辑:Maggie RIv 更新时间:3/13/2023 访问量:114

问:

检查不同排序算法的性能。我们得到了一个包含 500,000 个单词的.txt文件,这些文件将使用这些算法进行排序。我编写了读取文件并将单词存储在 String 数组中的方法。第一个计算行数,第二个使用计数器创建数组,但它仅适用于行数少得多的文件。我不能真正分享文本文件的内容,它只是一个每行包含 1 个单词的文件。ScannerScanner

当我尝试读取包含 500,000 行的文件时,我得到以下信息:

线程“main”中的异常 java.util.NoSuchElementException
在 java.base/java.util.Scanner.throwFor(Scanner.java:937) 在 java.base/java.util.Scanner.next(Scanner.java:1478) 在 Tester.readArray(Tester.java:81) 在 Tester.main(Tester.java:7)


您认为这是因为我的计算机不支持它,还是我需要更改方法? 这是我的方法:

public static String[] readArray(String file) {
    int wordCounter = 0;
    try {
        Scanner s1 = new Scanner(new File(file));
        while (s1.hasNextLine()) {
            wordCounter = wordCounter + 1;
            s1.next();
        }
        s1.close();
        String[]words = new String[wordCounter];
        Scanner s2 = new Scanner(new File(file));
        for (int i = 0; i < wordCounter; i = i + 1) {
            words[i] = s2.next();
        }
        return words;
    }
    catch (FileNotFoundException e) {
    
    }
    return null;
}
Java 数组 排序 java.util.scanner 读取文件

评论

0赞 Louis Wasserman 3/13/2023
这与您的计算机或任何东西无关,而是您的代码中的错误。我怀疑这与 和 之间的区别有关,而不是例如 或。我建议在包含两行的文件中对其进行测试。hasNextLine()next()hasNext()nextLine()
0赞 Abra 3/13/2023
您可以编辑您的问题并发布文本文件内容的样本吗?
0赞 MC Emperor 3/13/2023
此外,如果它被扔掉,你正在吞下它。FileNotFoundException
2赞 Jean-Baptiste Yunès 3/13/2023
不要使用 ,用于读行。撇开不谈,你为什么要把文件读两次?对它使用一个和每一行。然后根据需要将列表转换为数组。next()nextLine()ArrayListadd()
0赞 Maggie RIv 3/13/2023
@Abra嗨!它只是一个有 500,000 行的文件,每行只包含一个单词。

答:

2赞 Raboro 3/13/2023 #1

所以对我来说,替换为固定的异常。这与您的 PC 无关。 我认为当您在文件末尾有一个空行时,可能会发生此错误。因为,当我删除我正在读取的文件末尾的空行时,没有抛出异常。hasNextLine()hasNext()

评论

0赞 Maggie RIv 3/13/2023
我认为它有效!它仍在运行,它没有给我答案,我想由于行数可能需要一段时间?
0赞 Slaw 3/13/2023
@MaggieRIv 阅读 500,000 行,其中每行都是一个合法的单词(意味着它们不会很长),几乎不需要任何时间。一个 500,000 个元素的数组不是一个大数组(无论如何,按照“现实世界”的标准)。因此,排序也不应该花费太长时间。尽管您的性能测量代码可能仍需要一段时间,具体取决于其实现方式(例如,重复测试、每次读取文件,而不仅仅是按排序复制数组等)。但是,如果你发现你的程序花费了异常长的时间,我会确保你不会陷入某个地方的无限循环。
0赞 Maggie RIv 3/13/2023
@Slaw该死的,在那种情况下,我想我被卡住了。它适用于 100,000 行以下的文件
0赞 Slaw 3/13/2023
@MaggieRIv 您可以将打印语句放在代码中的重要位置,以查看是否正在访问该代码(如果没有,那么您就会卡在它之前)。或者,如果您知道如何使用调试器,则可以使用断点来执行相同的操作。此外,请确保您没有吞下异常(就像您在问题中的代码中所做的那样)。至少调用它们,以便您知道发生了错误(以及错误是什么以及抛出的位置)。FileNotFoundExceptionprintStackTrace()
0赞 Slaw 3/13/2023
@MaggieRIv 在我的计算机上,使用双通道方法可能需要 600-1000 毫秒(500,000 行)之间的任何时间。这不是一个很长的时间。虽然注意我使用了 和 ,但只计算/包括非空行。将其更改为一次性解决方案可将时间缩短大约一半(可以预见)。但是使用(及其方法)而不是将时间降低到大约 120 毫秒。我对为什么较慢的猜测是因为它基于正则表达式,而只看字符。ScannerhasNextLine()nextLine()ScannerBufferedReaderreadLine()ScannerScannerBufferedReader
0赞 Ahmet Duzduran 3/13/2023 #2

Scanner 的 hasNextLine() 方法检查输入中是否有另一行,无论该行是否为空,而 hasNext() 使用分隔符来检查另一个标记。使用 hasNext() 可能会解决您的问题。检查此内容以获取更多信息 hasNext() 与 hasNextLine()

但是,您正在使用 Scanner 类的 nextLine() 来获取总行数。这对于中小型文件可能很有效,但可能不适合无法放入内存的非常大的文件。

public static long countLines(String file) {
try {
    return Files.lines(Paths.get(file)).parallel().count();
} catch (IOException e) {
    e.printStackTrace();
    return -1;
}

}

此方法使用 parallel() 方法创建并行行行流,这可以通过使用多个线程并行处理行来提高大文件的性能。