<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, REQUEST_CODE); }
使用 OkHttp 发送文件:
File file = new File(filePath); // 本地文件路径 OkHttpClient client = new OkHttpClient(); RequestBody requestBody = new MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart("file", file.getName(), RequestBody.create(file, MediaType.parse("application/octet-stream"))) .build(); Request request = new Request.Builder() .url("https://your-server.com/upload") // 服务器上传接口 .post(requestBody) .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { / 处理失败 / } @Override public void onResponse(Call call, Response response) throws IOException { / 处理成功 / } });
使用 Retrofit 发送文件:
// 定义接口 @Multipart @POST("upload") Call<ResponseBody> uploadFile(@Part MultipartBody.Part file); // 调用接口 File file = new File(filePath); RequestBody requestBody = RequestBody.create(file, MediaType.parse("application/octet-stream")); MultipartBody.Part part = MultipartBody.Part.createFormData("file", file.getName(), requestBody); retrofit.create(ApiService.class).uploadFile(part).enqueue(new Callback<>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { / 成功逻辑 / } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { / 失败逻辑 / } });
进度监听(OkHttp):
// 自定义 RequestBody 统计上传进度 CountingRequestBody countingRequestBody = new CountingRequestBody(requestBody, new CountingRequestBody.Listener() { @Override public void onRequestProgress(long bytesWritten, long contentLength) { float progress = (float) bytesWritten / contentLength 100; // 更新 UI(需切换到主线程) } });
结合 RxJava/Coroutines:
io()
和 mainThread()
切换线程。withContext(Dispatchers.IO)
处理网络请求。@RestController public class FileController { @PostMapping("/upload") public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file) { try { String path = "server/path/" + file.getOriginalFilename(); file.transferTo(new File(path)); // 保存文件 return ResponseEntity.ok("Success"); } catch (Exception e) { return ResponseEntity.status(500).body("Error: " + e.getMessage()); } } }
步骤 | 代码/配置 |
---|---|
权限声明 | <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> |
动态权限申请 | ActivityCompat.requestPermissions() |
构建 Multipart 请求体 | MultipartBody.Builder().addFormDataPart() |
异步执行网络请求 | enqueue(new Callback()) 或 withContext(Dispatchers.IO) |
进度监听 | 自定义 CountingRequestBody 或拦截器统计字节数 |
服务器端接收文件 | @RequestParam MultipartFile + transferTo() |
解答:
在客户端构建多个 MultipartBody.Part
,
MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM); for (File file : fileList) { builder.addFormDataPart("files[]", file.getName(), RequestBody.create(file, MediaType.parse("application/octet-stream"))); }
服务器端需解析数组形式的文件参数(如 files[]
)。
解答:
示例(分片逻辑):
int chunkSize = 1024 1024; // 1MB for (int i = 0; i < file.length(); i += chunkSize) { byte[] chunk = Arrays.copyOfRange(fileBytes, i, Math.min(i + chunkSize, file.length())); // 上传 chunk 并记录进度 }