使用OkHttp在multipart中上传大文件

时间:2014-06-18 07:32:41

标签: android file-upload upload okhttp

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

5 个答案:

答案 0 :(得分:32)

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,但你需要的类应该是相同的。

答案 1 :(得分:30)

获取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());

             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_PNG, 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;
        }

为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();

GITHUB上传的演示:

我添加了Multiple Image Upload的答案:)

答案 2 :(得分:2)

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

}

答案 3 :(得分:0)

对于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 :(得分:0)

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

但是 OkHttp 提供了库 Okio,具有方便的类模拟流(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

中发帖和评论的所有人