Asynchronous File.copy in Java

Viewed 1232

Is there a way in Java to copy one file into another in an asynchrnous way? Something similar to Stream.CopyToAsync in C# is what I'm trying to find.

What I'm trying to achieve is to download a series of ~40 files from the Internet, and this is the best I've come up with for each file:

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

Where syncDownloadFile is:

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);
    }
}

But that means I have some blocking calls inside of the task executors, and I'd like to avoid that so I don't block too many executors at once.

I'm not sure if the C# method internally does the same (I mean, something has to be downloading that file right?).

Is there a better way to accomplish this?

1 Answers

AsynchronousFileChannel (AFC for short) is the right way to manage Files in Java with non-blocking IO. Unfortunately it does not provide a promises based (aka as Task in .net) API such as the CopyToAsync(Stream) of .Net.

The alternative RxIo library is built on top of the AFC and provides the AsyncFiles asynchronous API with different calling idioms: callbacks based, CompletableFuture (equivalent to .net Task) and also reactive streams.

For instance, copying from one file to another asynchronously can be done though:

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 */)

Note that continuations are invoked by a thread from the background AsynchronousChannelGroup.

Thus you may solve your problem using a non-blocking HTTP client, with ComplableFuture based API chained with the AsyncFiles use. For instance, AHC is valid choice. See usage here: https://github.com/AsyncHttpClient/async-http-client#using-continuations

Related