0

我正在尝试使用文件上传 API,该 API 需要以字节大小的块上传文件,该字节大小是从先前的 API 调用中指定的。所以....例如,如果文件很小,它会说以 1MB(以字节为单位)的块上传它,但它很大,它可能会说以 10MB 块上传它,如果它真的很小,它可能会简单地返回给我文件大小表明我应该一次全部上传。关键是我不提前知道。它还需要我将块的顺序指定为查询参数,因此我需要在循环浏览文件块时跟踪我尝试上传的块号。

无论如何,我在我的项目中使用 Retrofit / OkHttp 并认为这对 Okio 来说应该是一个很好的用例。这就是我目前所拥有的,它似乎有效。但是我是 Okio 的新手,不知道我是否遗漏了一些明显的东西,或者这是否可以以更好的方式完成。

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

您可以看到我正在绑定上传一个块,等待成功响应(来自 Java 8 ),然后使用更新的和再次CompletableFuture调用该方法。就像我说的,它有效,但我是 Okio 的新手,想知道我是否遗漏了一些明显的东西?chunkedUploadoffsetblockNumber

为什么我想使用 Okio 很大程度上是因为我要上传的文件通常在 30MB 到 1GB 之间,所以不要想一次将所有这些文件加载​​到内存中 :)。

4

1 回答 1

0

这是我使用 Okio 和 OkHttp 从 assets 文件夹中读取图像文件并将其作为 multipart/form-data 发送到请求正文中的代码。

你基本需要

  1. 创建一个 OkHttpClient
  2. 创建一个 RequestBody 对象
  3. 将您的 RequestBody 添加为 multipart/form-data
  4. 创建一个 Request 对象以将您的 RequestBody 和 Headers 添加到其中
  5. 使用 OkHttpClient 调用请求
  6. 将回调添加到您的队列中,以便您可以取回响应对象

    // Read image file from the assets folder
    BufferedSource img = Okio.buffer(Okio.source(getAssets().open("image.jpg")));
    byte[] image = img.readByteArray();

    // Create the OkHttpClient
    OkHttpClient client = new OkHttpClient().newBuilder().build();

    // Create the request body
    RequestBody rq =  RequestBody.create(MediaType.parse("image/jpeg"),image);

    RequestBody body = new MultipartBody.Builder().setType(MultipartBody.FORM)
            .addFormDataPart("image", "image.jpg", rq)
            .build();

    // Create the request and add the RequestBody to it
    Request request = new Request.Builder()
            .url(YOUR_URL)
            .method("POST", body)
            .addHeader("Authorization", "Bearer " + BEARER_TOKEN)
            .build();

    // Use OkHttpClient to call the request
    client.newCall(request).enqueue(new okhttp3.Callback() {
        @Override
        public void onFailure(okhttp3.Call call, IOException e) {
            Snackbar.make(upload, "Error", Snackbar.LENGTH_SHORT).show();

        }

        @Override
        public void onResponse(okhttp3.Call call, okhttp3.Response response) throws IOException {
            Snackbar.make(upload, "Success", Snackbar.LENGTH_SHORT).show();

        }
    });
于 2021-02-14T18:22:01.090 回答