如何使用Files.walk读取子目录中的所有文件一次?

Cac*_*eli 2 java file-io java-8 java-stream

我试图读取目录的所有子目录中的所有文件.我写了逻辑,但我做了一些稍微错误的事情,因为它在每个文件中读取两次.

为了测试我的实现,我创建了一个包含三个子目录的目录,每个子目录中包含10个文档.这应该是30份文件.

这是我正确阅读文档的测试代码:

String basePath = "src/test/resources/20NG";
Driver driver = new Driver();
List<Document> documents = driver.readInCorpus(basePath);
assertEquals(3 * 10, documents.size());
Run Code Online (Sandbox Code Playgroud)

哪里Driver#readInCorpus有以下代码:

public List<Document> readInCorpus(String directory)
{
    try (Stream<Path> paths = Files.walk(Paths.get(directory)))
    {
        return paths
                .filter(Files::isDirectory)
                .map(this::readAllDocumentsInDirectory)
                .flatMap(Collection::stream)
                .collect(Collectors.toList());
    }
    catch (IOException e)
    {
        e.printStackTrace();
    }
    return Collections.emptyList();
}

private List<Document> readAllDocumentsInDirectory(Path path)
{
    try (Stream<Path> paths = Files.walk(path))
    {
        return paths
                .filter(Files::isRegularFile)
                .map(this::readInDocumentFromFile)
                .collect(Collectors.toList());
    }
    catch (IOException e)
    {
        e.printStackTrace();
    }
    return Collections.emptyList();
}

private Document readInDocumentFromFile(Path path)
{
    String fileName = path.getFileName().toString();
    String outputClass = path.getParent().getFileName().toString();
    List<String> words = EmailProcessor.readEmail(path);
    return new Document(fileName, outputClass, words);
}
Run Code Online (Sandbox Code Playgroud)

当我运行测试用例时,我看到assertEquals失败的原因是检索到60个文件,而不是30个,这是不正确的.当我调试时,文档都被插入到列表中一次,然后以完全相同的顺序再次插入.

在我的代码中,我在文档中阅读两次?

Ore*_*est 5

这里的问题在于Files.walk(path)方法.您使用不当.所以它像树一样遍历你的文件系统.例如,你有3个文件夹 - /parent和2个孩子/parent/first,/parent/second. Files.walk("/parent")将为Paths每个文件夹(父项和2个子项)提供树,实际上这会在您的readInCorpus方法中发生.

然后,对于每个Path你在第二个方法readAllDocumentsInDirectory和同一个故事,它在这里遍历像树一样的文件夹.

对于readAllDocumentsInDirectory/parent路径,它将从两个孩子的文件夹中返回文档/parent/first/parent/second,然后你有2个以上的电话readAllDocumentsInDirectory/parent/first,/parent/second来自这两个文件夹是文件的回报.

这就是为什么你的文件翻倍.要修复它,你应该只调用readAllDocumentsInDirectoryPaths.get(basePath)参数的readInCorpus方法和删除方法.