You need to enable JavaScript to run this app. Android读取内部存储XLSX文件出现文件未找到及POI异常求解
优惠活动
大模型
产品
解决方案
定价
更多

Android读取内部存储XLSX文件出现文件未找到及POI异常求解

问题根因

你碰到的崩溃根本不是文件找不到——报错栈已经显示,getContentResolver.openInputStream()已经成功返回了文件流,代码已经走到POI初始化xlsx解析器的阶段。崩溃的直接原因有三个:

  • 安卓系统没有内置Java SE环境下的StAX(XML流式处理)实现,POI初始化时找不到com.bea.xml.stream.EventFactory类,直接抛出配置错误
  • 你之前以为的文件找不到错误,本质是代码里硬把content类型的Uri转本地文件路径的逻辑失效:安卓7.0之后通过存储访问框架(SAF)返回的Uri根本不支持直接转换为应用可访问的本地路径
  • 日志里的MQSService获取失败是小米定制系统的无关输出,和你的代码逻辑无关,无需处理
针对性解决步骤

1. 替换适配安卓的POI依赖

不要直接使用Java SE版本的POI依赖,否则一定会因为缺少安卓不兼容的系统类导致崩溃。在模块的build.gradle中引入以下依赖:

// 安卓适配版POI核心组件
implementation 'org.apache.poi:poi-android:5.2.3'
// xlsx格式解析扩展
implementation 'org.apache.poi:poi-ooxml:5.2.3'
// 补全缺失的StAX XML实现,解决EventFactory找不到的报错
implementation 'org.codehaus.woodstox:stax2-api:4.2.1'
implementation 'com.fasterxml.woodstox:woodstox-core:6.4.0'

依赖配置完成后执行一次Clean Project操作,避免旧的缓存类文件导致类冲突。

2. 修正SAF文件读取的逻辑漏洞

你代码里通过data.getData().getPath()拿到的字符串不是真实的本地文件路径,硬走文件路径访问的方式必然会触发文件未找到错误。
正确的读取逻辑是:拿到Uri后直接通过ContentResolver把文件内容拷贝到应用私有缓存目录生成临时文件,再用临时文件初始化POI对象——既避开了Uri转路径的无效逻辑,也能避免直接传InputStream导致的大文件内存溢出问题:

// onActivityResult中拿到选中Uri后的处理逻辑
if (requestCode == 1 && resultCode == RESULT_OK && data != null && data.getData() != null) {
    Uri selectedUri = data.getData();
    // 生成应用私有目录的临时文件
    File tempExcelFile = new File(getCacheDir(), "temp_selected_excel.xlsx");
    // 把选中的文件内容拷贝到临时文件
    try (InputStream is = getContentResolver().openInputStream(selectedUri);
         FileOutputStream fos = new FileOutputStream(tempExcelFile)) {
        byte[] buffer = new byte[8192];
        int readLen;
        while ((readLen = is.read(buffer)) != -1) {
            fos.write(buffer, 0, readLen);
        }
    } catch (IOException e) {
        e.printStackTrace();
        return;
    }
    // 用临时文件读取xlsx内容
    onReadClick(new FileInputStream(tempExcelFile));
}

3. 优化文件选择的Intent配置

把原来的全类型匹配的Intent,改成只匹配xlsx格式,避免用户误选其他格式文件导致解析错误:

if (v == btnChoose) {
    Intent pickFileIntent = new Intent(Intent.ACTION_GET_CONTENT);
    // 替换原来的.setType("*/*"),精准匹配xlsx格式
    pickFileIntent.setType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
    pickFileIntent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
    pickFileIntent.addCategory(Intent.CATEGORY_OPENABLE);
    startActivityForResult(Intent.createChooser(pickFileIntent, "选择Excel文件"), 1);
}
开发注意事项
  • 不要为了获取本地文件路径去申请全量存储权限,SAF框架本身不需要申请存储权限,通过拷贝临时文件的方式完全可以满足读取需求
  • 如果读取的xlsx文件超过10M,不要用XSSFWorkbook全量加载到内存,建议改用SAX流式解析,避免大文件导致应用崩溃
  • 不要在读取流的过程中反复关闭、重开流,POI解析压缩格式的xlsx文件需要随机访问流内容,一次性把文件拷贝到本地临时文件的方式性能最优

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.25 17:24:03