I'm trying to consume a file upload API that requires the file to be uploaded in chunks of a size in bytes that it specifies from a previous API call. So.... for example if the file is small it will say upload it in chunks of 1MB (in bytes) but it it is big it might say upload it in 10MB chunks and if it is really small it might simply return me the file size indicating that I should upload it all at once. The point is I don't know ahead of time. It also needs me to specify the order of the chunks as a query parameter so I need to keep track of what chunk number I am attempting to upload as I cycle through the chunks of the file.
Anyways I am using Retrofit / OkHttp in my project anyway and thought that this should be a good usecase for Okio. This is what I have at the moment and it seems to work. But I am new to Okio and don't know if I am missing something obvious or if this could be done in a better way.
private void chunkedUpload(int offset, int chunkSize, int blockNumber, @Nonnull CompletableFuture<Foo> future) {
File file = ...
String url = ...
try (final BufferedSource bufferedSource = Okio.buffer(Okio.source(file))) {
bufferedSource.skip(offset);
final Buffer buffer = new Buffer();
final boolean isFinal = !bufferedSource.request(chunkSize);
bufferedSource.read(buffer, chunkSize);
final RequestBody requestFile = RequestBody.create(buffer.readByteArray(), null);
upload(offset, chunkSize, url, requestFile, blockNumber, future, isFinal);
} catch (IOException e) {
future.completeExceptionally(e);
}
}
private void upload(int offset, int chunkSize, @Nonnull String url, @Nonnull RequestBody requestFile, int blockNumber, @Nonnull CompletableFuture<Foo> future, boolean isFinal) {
fileUloadService.uploadApp(url + "&block_number=" + blockNumber, requestFile)
.whenComplete((responseBody, throwable) -> {
if (throwable != null) {
future.completeExceptionally(throwable);
} else {
if (isFinal) {
future.complete();
return;
}
chunkedUpload(offset + chunkSize, chunkSize, blockNumber + 1, future);
}
});
}
You can see that I am tying upload a chunk, wait for the success response (from the Java 8 CompletableFuture
) and then call the chunkedUpload
method again with updated offset
and blockNumber
. Like I said, it works but I'm new to Okio and was wondering if I have missed something obvious?
Why I want to use Okio is pretty much because I'm going to be uploading files typically between 30MB and 1 GB so don't fancy loading all of that into memory at once :).
This is my code using Okio and OkHttp to read an image file from the assets folder and send it in the request body as a multipart/form-data.
You basic need to: