You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Retrofit上传File类型图片至数据库时出现文件路径不存在错误

图片上传失败(ENOENT错误)排查与解决

问题描述

处理用户资料Fragment时,点击按钮能正常显示图片,但调用uploadImage方法上传时进入onFailure回调,报错信息:

12006-12006 TAG                     com.example.sts_passenger            I  onFailure: /storage/emulated/0/Screenshot_20230523-073140_WhatsApp.jpg: open failed: ENOENT (No such file or directory)

上传方法代码:

public void uploadImage(File file){
        // Create a request body with File(file)
        RequestBody requestBody = RequestBody.create(MediaType.parse("image/*"), file);

        // Create a MultipartBody.Part from the request body
        MultipartBody.Part photo = MultipartBody.Part.createFormData("photo", file.getName(), requestBody);
        Log.i("TAG", "uploadImage: file name " + file.getName());

        // Api call
        Call<ResponseBody> req = Client.getInstance(Consts.BASE_URL_PASSENGER_AUTH).getRoute().uploadProfilePhoto(photo, session.getToken(), session.getPassenger().getPassengerId());
        Log.i("TAG", "uploadImage: enqueueing " + photo + " " + session.getPassenger().getPassengerId());
        req.enqueue(new Callback<ResponseBody>() {
          @Override
          public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
              if (response.isSuccessful()) {
                  Log.i("TAG", "onResponse: image uploaded" );
                  Log.i("TAG", "onResponse: success file name " + photo);
              }
          }

         @Override
          public void onFailure(Call<ResponseBody> call, Throwable t) {
             Log.i("TAG", "onFailure: " + t.getLocalizedMessage());
         }
        });
    }

API接口定义:

@Multipart
    @POST(Consts.ENDPOINT_UPLOAD_PROFILE_PIC)
    Call<ResponseBody> uploadProfilePhoto(
            @Part MultipartBody.Part photo,
            @Header("Authorization") String userSessionToken,
            @Path("passenger_id") Integer passengerId);

原因排查

  • 文件路径无效或文件不存在:报错明确指向文件找不到,虽然能显示图片,但可能显示时使用的是Uri而非真实文件路径,或文件在选择后被移动/删除,导致传入uploadImage的File对象路径失效。
  • 分区存储权限限制:Android 10+采用分区存储机制,直接访问外部存储根目录文件可能无读取权限,即使能显示图片,上传时读取文件会被系统拒绝,表现为文件找不到的错误。
  • API路径参数不匹配:接口使用@Path("passenger_id"),但Consts.ENDPOINT_UPLOAD_PROFILE_PIC可能未包含{passenger_id}占位符,导致请求路径错误(当前报错为文件问题,此为次要排查点)。

解决方法

  1. 验证文件真实状态
    在uploadImage方法开头添加文件存在性与可读性检查:

    if (!file.exists()) {
        Log.e("TAG", "uploadImage: File not found at path: " + file.getAbsolutePath());
        return;
    }
    if (!file.canRead()) {
        Log.e("TAG", "uploadImage: No read permission for file: " + file.getAbsolutePath());
        return;
    }
    

    若检查不通过,需重新获取正确的文件路径(比如从选择图片的Uri转换为真实路径,或通过ContentResolver读取文件流)。

  2. 适配Android分区存储

    • 对于Android 10及以上版本,避免直接使用File对象访问外部存储文件,改用ContentResolver读取文件流并转为RequestBody:
      // 假设imageUri是从相册选择得到的图片Uri
      InputStream inputStream = getContext().getContentResolver().openInputStream(imageUri);
      byte[] imageBytes = new byte[inputStream.available()];
      inputStream.read(imageBytes);
      RequestBody requestBody = RequestBody.create(MediaType.parse("image/*"), imageBytes);
      MultipartBody.Part photo = MultipartBody.Part.createFormData("photo", fileName, requestBody);
      
    • 确保已申请对应权限:Android 13+需申请READ_MEDIA_IMAGES,低版本需READ_EXTERNAL_STORAGE,并完成运行时动态权限申请。
  3. 检查API路径配置
    确认Consts.ENDPOINT_UPLOAD_PROFILE_PIC包含{passenger_id}占位符,例如:

    public static final String ENDPOINT_UPLOAD_PROFILE_PIC = "passengers/{passenger_id}/profile-photo";
    

    若缺少占位符,@Path("passenger_id")无法完成路径替换,会导致请求失败。

  4. 替换过时的OkHttp方法
    旧版RequestBody.create(MediaType, File)已过时,建议改用:

    RequestBody requestBody = RequestBody.create(file, MediaType.parse("image/*"));
    

    或直接使用MultipartBody.Part的重载方法:

    MultipartBody.Part photo = MultipartBody.Part.createFormData("photo", file.getName(), file);
    

内容的提问来源于stack exchange,提问作者dev.darron

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 19:22:35