如何以非阻塞方式在Java中列出目录中的文件?

3

使用Java中的nio包中的Files可以轻松地列出目录中的“文件”:

Stream<Path> paths = Files.list(Path.of("<folder>"))

然而调用Files.list(..)是阻塞的。如何以非阻塞方式列出目录中的文件?

更新

在“阻塞”的意义下,指的是不会阻止任何线程,这是响应式编程的上下文。在我的情况下,我正在使用来自 Spring项目反应器,并且我定义了一个像这样的方法:

public Flux<String> doStuffWithFilesInDirectory(String dir) {
    // Intellij complains that the call to "Files.list(..)" is inappropriate since it's a blocking call
    var fileStream = Files.list(Path.of(dir)); 
    return Flux.fromStream(fileStream). ..
}

1
“Blocking” 的确切含义是什么? - nullPointer
2个回答

2
硬盘的本质决定了它们无法立即提供信息。因此,可能的“非阻塞”解决方案为:
(a) 在单独的线程中进行同步阻塞执行;或
(b) 启动异步操作,并使用某些通知机制(回调、Future等)告诉您何时完成。
在后一种情况下,不仅需要通过某些Java方法实现,而且底层操作系统也需要提供支持。由于并非所有系统都提供“异步readdir”,我怀疑您也找不到Java接口。这是一个基于一般推理的论点,所以我可能是错误的 - 但我不会打赌。

2
如果您只想从调用线程异步运行Files.list,则无需寻找“替代”的文件API。 最基本的示例如下:
如果您只想从调用线程异步运行Files.list,则无需寻找“替代”的文件API。 最基本的示例如下:
Runnable lister = () -> {
    try {
        SomeReceivingClassOrInstance
            .someEventMethod(Files.list(Path.of("yourPath")));
    }
    catch (IOException ioe) {
        // TODO handle
        ioe.printStackTrace();
    }
};

您可以执行以下操作:
  • 在接收端实现一个方法,该方法采用Stream<Path>,并对其进行操作。
  • 使用new Thread(lister).start();异步调用您的Runnable,从您希望异步启动操作的位置开始。

请注意,有很多其他替代方案和更优雅/更高级的示例可用于异步运行操作。

这只是一个案例,以证明您不需要进一步查看nio API(例如,使用FileVisitor等)来使此过程异步化。

注意事项

经过思考:如果相反,您真正想要一个基于逐步“发现”的列表进行惰性填充的集合,则最好在其自己的线程中启动FileVisitor,并为每个条目填充线程安全的集合。


谢谢你的回复Mena,但是在你的例子中调用Files.list(..)仍然是一个阻塞调用,只不过它会在另一个线程中被阻塞。 - Johan
2
@Johan 确定。我添加了一个替代草案,以防您的要求是惰性填充集合而不是批量获取整个结果。如果不是这种情况,我认为我没有理解您的要求 - 可能需要添加一些上下文? - Mena
@Johan:除非你能找到一个本地的非阻塞API来列出文件,否则专门分配一个额外的线程来吸收阻塞是你唯一能做的事情。这不是一个好的解决方案吗? - Thilo
@Thilo 我相信这是一个好的解决方案,但在我看来它并没有完全回答问题。也许你的评论可以回答它,也许它不被支持?我会尝试更新问题,使它更清晰明了。 - Johan
4
磁盘的本质决定了它们不会立即提供信息。因此,可能的“非阻塞”解决方案是(a)在单独的线程中进行同步阻塞执行,或者(b)启动一个带有某些通知机制(回调、Future等)的异步操作来告诉您何时完成。在后一种情况下,不仅需要通过某个Java方法实现这一点,而且底层操作系统也需要提供支持。由于并非所有系统都提供“异步readdir”,我怀疑您也找不到Java接口。 - user10762593
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接