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

三星设备文件上传报错FileNotFoundException:ENOENT无文件或目录求助

解决三星设备文件上传时的FileNotFoundException问题

兄弟,我之前在三星设备上踩过一模一样的坑!结合你给出的代码场景,咱们来一步步解决这个FileNotFoundException(错误信息open failed: ENOENT (No such file or directory))的问题:

问题根源

三星设备对Android的Scoped Storage(分区存储)机制实现得更严格,加上自家文件管理器的特殊处理,导致你通过Intent获取到的Uri并不是直接的本地文件路径——如果你强行把Uri解析成文件路径去访问,自然会找不到文件抛出错误。

解决方案

核心思路:放弃直接解析Uri为文件路径,改用ContentResolver读取文件内容,这是符合Android 10及以上版本规范的做法,也能完美适配三星设备。

1. 替换文件选择Intent为更可靠的ACTION_OPEN_DOCUMENT

把原来的Intent改成ACTION_OPEN_DOCUMENT,它能通过系统文件选择器授予临时文件访问权限,比旧的ACTION_GET_CONTENT更稳定:

button_upload_attachment.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // Android 13+ 不需要READ_EXTERNAL_STORAGE权限,ACTION_OPEN_DOCUMENT会自动处理权限
        Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("*/*"); // 允许选择任意类型文件
        startActivityForResult(intent, REQUEST_CODE_FILE_PICK); // 自己定义REQUEST_CODE_FILE_PICK常量
    }
});

2. 通过ContentResolver读取文件内容并上传

在onActivityResult(或者用Jetpack的ActivityResultContracts)中,获取到Uri后,直接打开输入流读取文件内容,不要尝试转路径:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == REQUEST_CODE_FILE_PICK && resultCode == RESULT_OK && data != null) {
        Uri fileUri = data.getData();
        if (fileUri == null) return;

        try {
            // 打开文件输入流
            InputStream inputStream = getContentResolver().openInputStream(fileUri);
            if (inputStream == null) return;

            // 示例:用OkHttp上传文件(你可以替换成自己的上传逻辑)
            // 获取文件MIME类型和文件名
            String mimeType = getContentResolver().getType(fileUri);
            String fileName = getFileName(fileUri);

            RequestBody fileBody = RequestBody.create(MediaType.parse(mimeType), inputStream);
            MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", fileName, fileBody);

            // 构建上传请求
            OkHttpClient client = new OkHttpClient();
            Request request = new Request.Builder()
                    .url("你的服务器上传地址")
                    .post(MultipartBody.Builder()
                            .setType(MultipartBody.FORM)
                            .addPart(filePart)
                            .build())
                    .build();

            // 执行请求(建议用异步方式)
            client.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    e.printStackTrace();
                    // 处理上传失败
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    // 处理上传成功
                    if (response.isSuccessful()) {
                        // 逻辑代码
                    }
                }
            });

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}

// 辅助方法:从Uri获取文件名
private String getFileName(Uri uri) {
    String fileName = null;
    Cursor cursor = getContentResolver().query(uri,
            new String[]{OpenableColumns.DISPLAY_NAME},
            null, null, null);
    if (cursor != null && cursor.moveToFirst()) {
        fileName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
        cursor.close();
    }
    return fileName != null ? fileName : "unknown_file";
}

3. (可选)持久化文件访问权限

如果需要后续再次访问该文件,可以获取持久化权限:

final int takeFlags = data.getFlags()
        & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
getContentResolver().takePersistableUriPermission(fileUri, takeFlags);

额外注意点

  • 如果你的App targetSdkVersion >=33,不需要申请READ_EXTERNAL_STORAGE或WRITE_EXTERNAL_STORAGE权限,ACTION_OPEN_DOCUMENT会自动处理临时访问权限;
  • 不要尝试用第三方库强制解析Uri为文件路径,这种做法在三星设备上大概率失效,而且不符合Android规范。

内容的提问来源于stack exchange,提问作者Brinda Rathod

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:41:43