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

Android 10及以上设备无法创建文件/目录问题求助(附代码)

问题修复方案:Android 10无法创建目录及文件读取问题

核心问题分析

Android 10引入了分区存储(Scoped Storage),即使添加了android:requestLegacyExternalStorage="true",直接使用mkdir()创建目录可能因权限细节或路径处理失败;同时,Android 10及以上版本对Uri的直接路径解析不再可靠,导致文件读取异常。

修改后的完整代码

void Convert_to_PDF(Uri path) throws IOException, DocumentException {
    // 1. 修复目录创建逻辑:改用mkdirs()并添加错误日志
    File storageDir = new File(Environment.getExternalStorageDirectory() + "/MultiFileCon");
    if (!storageDir.exists()) {
        boolean isDirCreated = storageDir.mkdirs();
        if (!isDirCreated) {
            Log.e("PDF_CONVERT", "目录创建失败:" + storageDir.getAbsolutePath());
            Toast.makeText(this, "无法创建存储目录,请检查权限", Toast.LENGTH_SHORT).show();
            return;
        }
    }

    // 生成带时间戳的PDF文件名
    SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH.mm.ss", Locale.getDefault());
    String pdfFileName = formatter.format(new Date()) + ".pdf";
    File pdffilex = new File(storageDir.getAbsolutePath(), pdfFileName);
    Log.d("PDF_PATH", "生成的PDF路径:" + pdffilex.getAbsolutePath());

    // 2. 修复Android 10+的文件读取逻辑:用ContentResolver替代路径解析
    InputStream input_document;
    if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        Toast.makeText(this, "Android版本:" + android.os.Build.VERSION.SDK_INT, Toast.LENGTH_LONG).show();
        Log.d("VERSION", "当前版本:Android 10+");
        // 通过ContentResolver直接获取文件输入流,避免Uri路径解析问题
        input_document = getContentResolver().openInputStream(path);
    } else {
        input_document = new FileInputStream(new File(PathUtil.getPath(this, path)));
    }

    // Excel转PDF核心逻辑
    HSSFWorkbook my_xls_workbook = new HSSFWorkbook(input_document);
    HSSFSheet my_worksheet = my_xls_workbook.getSheetAt(0);
    Iterator<Row> rowIterator = my_worksheet.iterator();

    Document iText_xls_2_pdf = new Document();
    PdfWriter.getInstance(iText_xls_2_pdf, new FileOutputStream(pdffilex));
    iText_xls_2_pdf.open();

    PdfPTable my_table = new PdfPTable(7);
    PdfPCell table_cell;

    while (rowIterator.hasNext()) {
        Row row = rowIterator.next();
        Iterator<Cell> cellIterator = row.cellIterator();
        while (cellIterator.hasNext()) {
            Cell cell = cellIterator.next();
            switch (cell.getCellType()) {
                case Cell.CELL_TYPE_STRING:
                    table_cell = new PdfPCell(new Phrase(cell.getStringCellValue()));
                    my_table.addCell(table_cell);
                    break;
                // 新增:处理数字、日期类型的单元格
                case Cell.CELL_TYPE_NUMERIC:
                    if (DateUtil.isCellDateFormatted(cell)) {
                        table_cell = new PdfPCell(new Phrase(formatter.format(cell.getDateCellValue())));
                    } else {
                        table_cell = new PdfPCell(new Phrase(String.valueOf(cell.getNumericCellValue())));
                    }
                    my_table.addCell(table_cell);
                    break;
            }
        }
    }

    iText_xls_2_pdf.add(my_table);
    iText_xls_2_pdf.close();
    input_document.close();
    my_xls_workbook.close(); // 释放Workbook资源

    Toast.makeText(this, "PDF已生成:" + pdfFileName, Toast.LENGTH_LONG).show();
}

关键修改点说明

  1. 目录创建优化
    • 替换mkdir()为mkdirs():确保父目录不存在时也能递归创建
    • 添加错误日志和Toast提示:便于排查目录创建失败的具体原因
  2. Android 10+文件读取修复
    • 放弃Uri路径拆分的方式,改用getContentResolver().openInputStream(path)直接获取文件流,完全适配分区存储规则
    • 版本判断改为>= Build.VERSION_CODES.Q(对应Android 10,SDK 29),更准确
  3. 其他优化
    • 新增Locale.getDefault()避免SimpleDateFormat的本地化问题
    • 添加Excel数字/日期类型的处理逻辑,提升兼容性
    • 关闭HSSFWorkbook释放资源,避免内存泄漏
    • 增加PDF生成成功的提示

额外注意事项

  • 确保Dexter权限申请逻辑正确,在调用Convert_to_PDF前已获取WRITE_EXTERNAL_STORAGE和READ_EXTERNAL_STORAGE权限
  • 若后续升级到Android 11+,建议逐步迁移到MediaStore API存储文件,彻底适配分区存储

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 15:35:36