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

Android保存PDF到外部存储遇EPERM权限错误,求解决

背景与问题

尝试将PDF文件保存到外部存储时,出现以下错误:

Caused by: android.system.ErrnoException: open failed: EPERM (Operation not permitted)

1) 权限检查逻辑

应用启动时会执行存储权限检查:

private fun initAndCheckPermissions() {
    bmp = BitmapFactory.decodeResource(resources, R.drawable.logo_nuin_nomb_subt)
    scaledbmp = Bitmap.createScaledBitmap(bmp, 140, 140, false)
    if (checkPermissions()) {
        // 权限授予后提示
        Toast.makeText(requireContext(), "Permissions Granted..", Toast.LENGTH_SHORT).show()
    } else {
        requestPermission()
    }
}
fun requestPermission() {
    ActivityCompat.requestPermissions(
        requireActivity(),
        arrayOf(
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE
        ), PERMISSION_CODE
    )
}

override fun onRequestPermissionsResult(
    requestCode: Int,
    permissions: Array<out String>,
    grantResults: IntArray
) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    if (requestCode == PERMISSION_CODE) {
        if (grantResults.size > 0) {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1]
                == PackageManager.PERMISSION_GRANTED) {
                Toast.makeText(requireContext(), "Permission Granted..", Toast.LENGTH_SHORT).show()
            } else {
                requireActivity().finish()
            }
        }
    }
}

PDF生成逻辑

用户点击按钮时,生成包含文本和图片的PDF文件:

@RequiresApi(Build.VERSION_CODES.KITKAT)
fun generatePDF() {
    var pdfDocument: PdfDocument = PdfDocument()
    var paint: Paint = Paint()
    var title: Paint = Paint()
    var myPageInfo: PdfDocument.PageInfo? =
        PdfDocument.PageInfo.Builder(pageWidth, pageHeight, 1).create()
    var myPage: PdfDocument.Page = pdfDocument.startPage(myPageInfo)
    var canvas: Canvas = myPage.canvas
    canvas.drawBitmap(scaledbmp, 56F, 40F, paint)
    title.typeface = Typeface.create(Typeface.DEFAULT, Typeface.NORMAL)
    title.textSize = 15F
    title.color = ContextCompat.getColor(requireContext(), R.color.purple_200)
    canvas.drawText("A portal for IT professionals.", 209F, 100F, title)
    canvas.drawText("Geeks for Geeks", 209F, 80F, title)
    title.typeface = Typeface.defaultFromStyle(Typeface.NORMAL)
    title.color = ContextCompat.getColor(requireContext(), R.color.purple_200)
    title.textSize = 15F
    title.textAlign = Paint.Align.CENTER
    canvas.drawText("This is sample document which we have created", 396F, 560F, title)
    pdfDocument.finishPage(myPage)
    val file: File = File(Environment.getExternalStorageState(), "GFG.pdf")
    pdfDocument.writeTo(FileOutputStream(file))
    Toast.makeText(requireContext(), "PDF file generated..", Toast.LENGTH_SHORT).show()
    pdfDocument.close()
}

核心问题

错误触发自以下代码行:

val file: File = File(Environment.getExternalStorageState(), "GFG.pdf")

对应的错误信息:

Caused by: android.system.ErrnoException: open failed: EPERM (Operation not permitted)

解决方案

1. 修复路径参数错误

Environment.getExternalStorageState()返回的是存储状态字符串(如mounted),并非存储目录路径。需替换为正确的目录获取方法:

  • Android 9及以下:使用Environment.getExternalStorageDirectory()
  • Android 10+:受Scoped Storage限制,需按以下方案调整

2. 适配Android 10+存储策略

方案A:使用应用专属外部存储(无需额外权限)

此目录下的文件仅当前应用可访问,卸载应用时会被自动删除,无需申请存储权限:

// 获取应用专属文档目录
val dir = requireContext().getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS)
val file = File(dir, "GFG.pdf")
方案B:保存到公共目录(需权限适配)

若必须保存到公共目录:

  • Android 10-12:在AndroidManifest.xml的<application>标签中添加android:requestLegacyExternalStorage="true",兼容旧存储模式
  • Android 13+:申请READ_MEDIA_*系列权限,写入公共目录需使用MediaStore API;或申请MANAGE_EXTERNAL_STORAGE权限(需通过Google Play审核)

3. 权限逻辑优化

Android 10+版本中,即使申请了WRITE_EXTERNAL_STORAGE权限,在Scoped Storage模式下也无法直接写入公共目录,需按上述方案调整存储路径或权限策略。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 18:45:40