【问题标题】:Uploading a large file in multipart using OkHttp使用 OkHttp 分段上传大文件
【发布时间】:2014-08-08 09:29:39
【问题描述】:

在 Android 中使用 OKhttp 在多部分中上传单个大文件(更具体地说,到 s3)有哪些选择?

【问题讨论】:

  • 你能更新使用的代码来解决这个问题吗?
  • 你也可以关注这个stackoverflow.com/a/34037063/1318946
  • 这些解决方案都不能处理“大”文件。请将它们全部删除,以便记录真正的解决方案。

标签: android file-upload upload okhttp


【解决方案1】:

OkHttp Recipes page,此代码将图像上传到 Imgur:

private static final String IMGUR_CLIENT_ID = "...";
private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");

private final OkHttpClient client = new OkHttpClient();

public void run() throws Exception {
  // Use the imgur image upload API as documented at https://api.imgur.com/endpoints/image
  RequestBody requestBody = new MultipartBuilder()
      .type(MultipartBuilder.FORM)
      .addPart(
          Headers.of("Content-Disposition", "form-data; name=\"title\""),
          RequestBody.create(null, "Square Logo"))
      .addPart(
          Headers.of("Content-Disposition", "form-data; name=\"image\""),
          RequestBody.create(MEDIA_TYPE_PNG, new File("website/static/logo-square.png")))
      .build();

  Request request = new Request.Builder()
      .header("Authorization", "Client-ID " + IMGUR_CLIENT_ID)
      .url("https://api.imgur.com/3/image")
      .post(requestBody)
      .build();

  Response response = client.newCall(request).execute();
  if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

  System.out.println(response.body().string());
}

您需要将其适应 S3,但您需要的类应该相同。

【讨论】:

  • 谢谢杰西。假设我知道内容长度,是否有任何方法可以跟踪请求的进度?
  • @TomerWeller 您可以创建一个自定义 RequestBody 来跟踪移动的字节。您需要包装传递给 RequestBody 的 Sink。
  • Tomer,在这里查看我的答案:stackoverflow.com/questions/25962595/…
  • 我想通了。使用 imgur,您不必提供文件名,因此可以像我在上述评论中所做的那样发送图像字节。但是,对于我实际上正在与之交谈的 API,它需要一个文件名,所以这有效:multipartBuilder.addFormDataPart("image", fileName, entry.getValue());
  • MultiPartBuilder 现在称为 MultipartBody.Builder,参见:stackoverflow.com/questions/34676044/…
【解决方案2】:

获取 OkHttp 2.1,并使用MultipartBuilder.addFormDataPart(),它将文件名作为参数。

       /**
         * Upload Image
         *
         * @param memberId
         * @param sourceImageFile
         * @return
         */
        public static JSONObject uploadImage(String memberId, String sourceImageFile) {
    
            try {
                File sourceFile = new File(sourceImageFile);
    
                Log.d(TAG, "File...::::" + sourceFile + " : " + sourceFile.exists());
             //Determining the media type        
             final MediaType MEDIA_TYPE = sourceImageFile.endsWith("png") ? 

                MediaType.parse("image/png") : MediaType.parse("image/jpeg");
                
    
                RequestBody requestBody = new MultipartBuilder()
                        .type(MultipartBuilder.FORM)
                        .addFormDataPart("member_id", memberId)
                        .addFormDataPart("file", "profile.png", RequestBody.create(MEDIA_TYPE, sourceFile))
                        .build();
    
                Request request = new Request.Builder()
                        .url(URL_UPLOAD_IMAGE)
                        .post(requestBody)
                        .build();
    
                OkHttpClient client = new OkHttpClient();
                Response response = client.newCall(request).execute();
                return new JSONObject(response.body().string());
    
            } catch (UnknownHostException | UnsupportedEncodingException e) {
                Log.e(TAG, "Error: " + e.getLocalizedMessage());
            } catch (Exception e) {
                Log.e(TAG, "Other Error: " + e.getLocalizedMessage());
            }
            return null;
        }

#Edited for okhttp3:

compile 'com.squareup.okhttp3:okhttp:3.4.1'

RequestBody 替换为:

RequestBody requestBody = new MultipartBody.Builder()
                    .setType(MultipartBody.FORM)
                    .addFormDataPart("uploaded_file", filename, RequestBody.create(MEDIA_TYPE_PNG, sourceFile))
                    .addFormDataPart("result", "my_image")
                    .build();

#Uploaded Demo on GITHUB: ##我已经为Multiple Image Upload 添加了我的答案:)

【讨论】:

  • @Pratik Butani 它可以工作,但我想从 API 读取响应。我必须根据响应执行另一项任务。
  • @droid_dev 其返回 JSONObject 返回值。检查一下。
  • 我使用的是入队方法而不是执行。我们可以通过 multipart 发送多张图片吗??
  • @PratikButani .addFormDataPart("result", "my_image") 是什么?!
  • @priyankasinghal 更改MediaType.parse("application/pdf")
【解决方案3】:

对于 okhttp 4.* 使用 MultipartBody.Builder:

fun postMultipart(url: String, text: String, imagePath: String, imageFileName: String): okhttp3.Response? {
    val file = File(imagePath)
    val fileRequestBody = file.asRequestBody("image/jpeg".toMediaType())
    val requestBody = MultipartBody.Builder()
        .addFormDataPart("text", text)
        .addFormDataPart("image", imageFileName, fileRequestBody)
        .build()

    val request = getRequestBuilder(url)
        .post(requestBody)
        .build()

    val client = OkHttpClient()
    client.newCall(request).execute().use { response ->
        return response
    }
}

【讨论】:

    【解决方案4】:

    对于 okhttp 2.6.0 {

        try {
            File file = new File(Environment.getExternalStorageDirectory().getPath()+"/xxx/share/" + "ic_launcher.png");
            String contentType = file.toURL().openConnection().getContentType();
            RequestBody fileBody = RequestBody.create(MediaType.parse(contentType), file);
    
            RequestBody requestBody = new MultipartBuilder()
                    .type(MultipartBuilder.FORM)
                    .addFormDataPart("fileUploadType","1")
                    .addFormDataPart("miniType",contentType)
                    .addFormDataPart("ext",file.getAbsolutePath().substring(file.getAbsolutePath().lastIndexOf(".")))
                    .addFormDataPart("fileTypeName","img")
                    .addFormDataPart("Filedata","ss.png",fileBody)
                    .build();
            Request request = new Request.Builder()
                    .url(Contains.MULTIPARTY_POST)
                    .post(requestBody)
                    .build();
            okHttpClient.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Request request, IOException e) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            tvGetNews.setText("upload fail");
                        }
                    });
                }
    
                @Override
                public void onResponse(Response response) throws IOException {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            tvGetNews.setText("upload success");
                        }
                    });
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
    
    }
    

    【讨论】:

      【解决方案5】:

      在 Android 中,您通常与 Uri 分开。使用大文件时的问题是,如果您尝试将完整流读取到字节数组(内存中的所有内容),或者最终使用 Uri 流创建无用文件,您很容易遇到OutOfMemoryError。这是因为RequestBody 不支持从Stream 创建(因为有时OkHttp 需要多次读取,例如,如果您获得30X 重定向)或Uri(因为OkHttp 不是Android 库)。

      但是 OkHttp 提供了 Okio 库,提供了方便的类模拟 Streams(SourceSink)和更方便的内部使用。

      因此,要创建一个 BodyRequest 形成一个 Uri 避免任何 OutOfMemoryError 由于大文件创建它:

      private static final MediaType MULTIPART_FOR_DATA = MediaType.parse("multipart/form-data");
      
      private @NotNull RequestBody getFilePart(Uri largeFileUri) {
      
              return new RequestBody() {
                  @Override
                  public MediaType contentType() {
                      return MULTIPART_FOR_DATA;
                  }
      
                  @Override
                  public void writeTo(@NotNull BufferedSink sink) throws IOException {
                      try (Source source = Okio.source(context.getContentResolver().openInputStream(mediaUri))) {
                          sink.writeAll(source);
                      }
                  }
              };
          }
      

      感谢大家在以下 GitHub 线程 https://github.com/square/okhttp/issues/3585 中发帖和评论

      【讨论】:

        猜你喜欢
        • 2014-11-15
        • 2015-08-01
        • 2021-01-19
        • 2016-06-20
        • 2016-06-06
        • 1970-01-01
        • 2021-04-15
        • 2014-06-24
        相关资源
        最近更新 更多