Java中的异步文件复制

5

在Java中有没有一种异步的方式将一个文件复制到另一个文件?我想找类似于C#中Stream.CopyToAsync方法的解决方案。

我的目标是从互联网上下载一系列约40个文件,以下是我为每个文件想出的最佳解决方案:

CompletableFuture.allOf(myFiles.stream()
        .map(file -> CompletableFuture.supplyAsync(() -> syncDownloadFile(file)))
        .toArray(CompletableFuture[]::class))
    .then(ignored -> doSomethingAfterAllDownloadsAreComplete());

其中 syncDownloadFile 是:

private void syncDownloadFile(MyFile file) {
    try (InputStream is = file.mySourceUrl.openStream()) {
        long actualSize = Files.copy(is, file.myDestinationNIOPath);
        // size validation here
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

但这意味着我在任务执行器内有一些阻塞调用,我希望避免这种情况,以便不会一次阻塞太多执行器。

我不确定C#方法是否内部执行相同的操作(我的意思是,某些内容必须下载该文件,对吗?)。

有更好的方法来完成这个任务吗?


1
你应该将一个CompletableFuture数组传递给allOf,而不是一个MyFile数组。一旦调用toArray,它将阻塞直到填充所有的MyFiles。 - Novaterata
@Novaterata 嗯,谢谢。我稍微修改了一下代码,以删除公司的私人内容,但在过程中出现了一些问题。 - Daniel
因此,您应该将最终的CompletableFuture分解为一个变量。然后,您可以执行任何其他需要做的事情,并在需要最终结果时调用completableFuture.get()。它不会阻塞,直到您调用get()或complete()或类似方法,但它已经开始工作了。 - Novaterata
https://dev59.com/TnA75IYBdhLWcg3wFEsI#3489549 - boateng
因为它们每个都在执行Files.copy,这是一个阻塞调用。 - Daniel
显示剩余2条评论
1个回答

2

AsynchronousFileChannel(简称AFC)是Java中使用非阻塞IO管理文件的正确方式。不幸的是,它没有提供基于promises的API(在.NET中称为Task),例如.NET的CopyToAsync(Stream)

替代方案RxIo库是建立在AFC之上的,并提供了不同的调用习惯:回调CompletableFuture(相当于.NET的Task)和反应流。

例如,从一个文件异步复制到另一个文件可以通过以下方式完成:

Path in = Paths.get("input.txt");
Path out = Paths.get("output.txt");
AsyncFiles
      .readAllBytes(in)
      .thenCompose(bytes -> AsyncFiles.writeBytes(out, bytes))
      .thenAccept(index -> /* invoked on completion */)

请注意,继续由后台AsynchronousChannelGroup的线程调用。

因此,您可以使用非阻塞HTTP客户端解决问题,并使用基于ComplableFuture的API链接使用AsyncFiles。例如,AHC是有效的选择。请参见此处的用法:https://github.com/AsyncHttpClient/async-http-client#using-continuations


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