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

无法将SD卡中的图片上传至PHP服务器问题咨询

解决Android Upload Service无法上传SD卡文件的问题

嘿,这个问题我之前也碰到过!大概率是外置SD卡的文件访问权限不足或者路径处理不对导致的,我给你整理几个靠谱的解决步骤:

1. 先把必要的权限配置到位

从Android 6.0开始,访问外置存储不仅要在清单文件里声明权限,还得动态申请。首先在AndroidManifest.xml里加上这些权限:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Android 10及以上需要这个权限访问非媒体类文件 -->
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
    android:minSdkVersion="30" />

然后在代码里动态申请读写权限(针对API 23+):

private static final int REQUEST_STORAGE_PERMISSION = 100;

// 在合适的地方(比如Activity onCreate)检查权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
        != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(this,
            new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE},
            REQUEST_STORAGE_PERMISSION);
}

如果是Android 10+,MANAGE_EXTERNAL_STORAGE权限需要引导用户去设置里手动开启,代码可以这么写:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    if (!Environment.isExternalStorageManager()) {
        Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
        Uri uri = Uri.fromParts("package", getPackageName(), null);
        intent.setData(uri);
        startActivity(intent);
    }
}

2. 别直接用绝对路径,试试Storage Access Framework(SAF)

外置SD卡的绝对路径在不同设备上可能不一样,而且Android 10+的分区存储会限制直接访问绝对路径。建议用SAF让用户选择文件,这样能拿到合法的Uri来访问文件:

private static final int REQUEST_PICK_IMAGE = 200;

// 触发文件选择
private void pickImageFromSDCard() {
    Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
    intent.addCategory(Intent.CATEGORY_OPENABLE);
    intent.setType("image/*");
    startActivityForResult(intent, REQUEST_PICK_IMAGE);
}

// 处理选择结果
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == REQUEST_PICK_IMAGE && resultCode == RESULT_OK) {
        Uri imageUri = data.getData();
        // 用Uri来上传,而不是绝对路径
        try {
            String uploadId = UUID.randomUUID().toString();
            new MultipartUploadRequest(this, uploadId, Constant.URL + "/lecture/save?token=" + token)
                    .addFileToUpload(getRealPathFromUri(imageUri), "notes_image")
                    .addParameter("class_code", classId)
                    .addParameter("section_code", sectionNameId)
                    // 补充你的其他参数
                    .startUpload();
        } catch (Exception e) {
            e.printStackTrace();
            Toast.makeText(this, "上传初始化失败:" + e.getMessage(), Toast.LENGTH_SHORT).show();
        }
    }
}

// 辅助方法:把Uri转成真实路径(Android 10以下可用)
private String getRealPathFromUri(Uri uri) {
    String[] projection = {MediaStore.Images.Media.DATA};
    Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
    if (cursor == null) return null;
    int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
    cursor.moveToFirst();
    String path = cursor.getString(columnIndex);
    cursor.close();
    return path;
}

如果是Android 10+,getRealPathFromUri可能拿不到路径,这时候可以试试直接传入Uri到Upload Service(最新版本的库支持这个操作),把addFileToUpload换成addFileToUpload(uri, "notes_image")就行。

3. 检查Upload Service的版本和配置

确保你用的是最新版的Android Upload Service,旧版本可能对SD卡的支持有bug。在build.gradle里更新依赖:

implementation 'net.gotev:uploadservice:4.7.0' // 可替换为官网最新版本号

同时确认AndroidManifest.xml里的服务配置正确:

<service
    android:name="net.gotev.uploadservice.UploadService"
    android:permission="android.permission.BIND_JOB_SERVICE"
    android:exported="false">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
    </intent-filter>
</service>

4. 先确认文件能被读取

上传前先做个小检查,确保SD卡上的文件确实能被你的App访问:

File imageFile = new File(f.getAbsolutePath());
if (!imageFile.exists()) {
    Toast.makeText(this, "文件不存在!", Toast.LENGTH_SHORT).show();
    return;
}
if (!imageFile.canRead()) {
    Toast.makeText(this, "没有权限读取这个文件!", Toast.LENGTH_SHORT).show();
    return;
}
// 没问题再执行上传逻辑

内容的提问来源于stack exchange,提问作者Sikshya Maharjan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 06:34:56