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

Android保存PDF报EPERM错误 已申请读写权限仍触发FileNotFoundException如何解决

安卓PDF存储EPERM异常解决方案

核心问题根因

  • 权限申请是异步操作:你当前调用checkPermission后直接执行文件写入逻辑,此时系统还未完成权限审批,调用写文件逻辑时自然没有存储权限
  • 分区存储适配问题:如果你的App targetSdkVersion >= 29(安卓10及以上),系统默认开启分区存储限制,禁止直接写入外部存储根目录Environment.getExternalStorageDirectory(),哪怕申请了存储权限也会被拒绝
  • 权限规则变更:安卓13(API 33)及以上版本,WRITE_EXTERNAL_STORAGE权限已经完全废弃,申请该权限不会有任何效果

修复步骤

1. 处理权限申请异步逻辑

将文件写入逻辑封装为独立方法,在系统权限回调onRequestPermissionsResult中判断权限申请通过后,再执行写入逻辑,不要申请权限后立刻执行写入。

2. 适配分区存储规则

二选一即可:

  • 方案1(优先推荐,无需申请权限):将PDF存入应用专属外部目录,该目录只有你的App可以访问,不需要申请任何存储权限。路径通过getExternalFilesDir(null)获取,对应存储位置为/storage/emulated/0/Android/data/你的应用包名/files/
  • 方案2(需要存入公共目录用户可见):使用MediaStore API写入公共的下载/文档目录,不要直接使用File路径操作公共存储区域。
  • 临时过渡方案:如果需要快速兼容,可在AndroidManifest.xml的application节点添加属性android:requestLegacyExternalStorage="true",可在安卓10设备上绕过分区存储限制,该方案在安卓11及以上已经失效。

3. 适配不同版本权限规则

  • 运行安卓9及以下(API <=28):正常申请READ_EXTERNAL_STORAGE、WRITE_EXTERNAL_STORAGE权限
  • 运行安卓10-12(API 29-32):申请READ_EXTERNAL_STORAGE即可,写权限不需要单独申请
  • 运行安卓13及以上(API >=33):如果只是读写应用自身的文件,不需要申请任何存储权限;如果需要读取其他应用的媒体文件,按需申请READ_MEDIA_*系列权限即可。

修改后代码示例

// 先申请权限,再在回调中执行写入
checkPermission(Manifest.permission.READ_EXTERNAL_STORAGE, 101);

// 封装PDF写入逻辑
private void savePdf() {
    // 改成应用专属外部目录,不需要权限
    File file = new File(getExternalFilesDir(null), "/myFile.pdf");
    try {
        PdfReader reader = new PdfReader(getResources().openRawResource(R.raw.bail_1));
        try {
            PdfWriter writer = new PdfWriter(new FileOutputStream(file));
            PdfDocument pdf = new PdfDocument(reader, writer);
            pdf.close();
            writer.close();
            reader.close();
            Toast.makeText(this, "OK", Toast.LENGTH_SHORT).show();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            Toast.makeText(this,"FileNotFoundException: " + e.getMessage(), Toast.LENGTH_SHORT).show();
            return;
        }
    } catch (IOException e) {
        e.printStackTrace();
        Toast.makeText(this,"IOException: " + e.getMessage(), Toast.LENGTH_SHORT).show(); 
        return;
    }
}

// 重写权限申请回调
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == 101) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // 权限申请通过,执行写入
            savePdf();
        } else {
            Toast.makeText(this, "需要存储权限才能保存文件", Toast.LENGTH_SHORT).show();
        }
    }
}

private void checkPermission(String permission, int requestCode) {
    if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this, new String[]{permission}, requestCode);
    } else {
        // 已经有权限,直接执行写入
        savePdf();
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 12:18:04