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

Jetpack Compose环境下读取Excel文件失败,存储路径存疑求助

Android加载Excel文件崩溃的解决方案

核心崩溃原因排查

  • 格式不匹配:HSSFWorkbook仅支持.xls格式,你的文件是.xlsx,必须改用XSSFWorkbook处理(需确保gradle中已引入poi-ooxml依赖)。
  • 硬编码路径错误:你写的/Internal storage/是文件管理器的显示别名,并非系统真实路径,直接硬编码会导致文件找不到。
  • 权限缺失:访问共享目录(如Documents)需要对应权限,Android版本不同,权限要求也有差异。

方案一:应用专属存储(无需权限,推荐)

应用专属存储的文件仅当前应用可访问,无需申请权限,路径通过系统API获取即可:

// 获取应用专属外部存储目录(优先选外部,内部存储作为 fallback)
val fileDir = context.getExternalFilesDir(null) ?: context.filesDir
val file = File(fileDir, "Sweeps.xlsx")

if (!file.exists()) {
    Log.e("MO", "文件不存在")
    return
}

try {
    FileInputStream(file).use { inputStream ->
        // 用XSSFWorkbook处理xlsx格式文件
        val workbook = XSSFWorkbook(inputStream)
        // 检查工作表是否存在
        val sheet1 = workbook.getSheet("Handicap Index & Course Play...") ?: run {
            Log.e("MO", "指定工作表不存在")
            workbook.close()
            return
        }
        // 检查行是否存在
        val row = sheet1.getRow(0) ?: run {
            Log.e("MO", "第0行不存在")
            workbook.close()
            return
        }
        // 检查单元格是否存在
        val cell = row.getCell(2) ?: run {
            Log.e("MO", "第2列单元格不存在")
            workbook.close()
            return
        }
        // 兼容不同单元格类型
        val cellData = when (cell.cellType) {
            CellType.STRING -> cell.stringCellValue
            CellType.NUMERIC -> cell.numericCellValue.toString()
            else -> "无法识别的单元格类型"
        }
        Log.i("MO", "My Excel value is : $cellData")
        workbook.close()
    }
} catch (e: Exception) {
    Log.e("MO", "读取Excel失败", e)
}

把Sweeps.xlsx放到应用专属目录(即Internal storage/Android/com.example.my_app/files)即可正常读取。


方案二:共享Documents目录(需权限/存储访问框架)

如果要让文件在应用间共享,分Android版本处理:

Android 10及以下

  1. 在AndroidManifest.xml声明权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  1. 动态申请权限后,通过系统API获取Documents路径:
// 先检查权限,未授权则申请
if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), 100)
    return
}

// 获取系统Documents目录
val documentsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)
val file = File(documentsDir, "Sweeps.xlsx")

// 后续读取逻辑同方案一(用XSSFWorkbook+错误处理)

Android 11+

直接申请存储权限无法访问共享目录,推荐用**存储访问框架(SAF)**让用户手动选择文件:

// 启动文件选择器,限定xlsx格式
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
    addCategory(Intent.CATEGORY_OPENABLE)
    type = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
}
startActivityForResult(intent, 200)

// 在回调中处理选中的文件
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == 200 && resultCode == Activity.RESULT_OK) {
        data?.data?.let { uri ->
            try {
                contentResolver.openInputStream(uri)?.use { inputStream ->
                    val workbook = XSSFWorkbook(inputStream)
                    // 后续处理逻辑同方案一
                    workbook.close()
                }
            } catch (e: Exception) {
                Log.e("MO", "读取Excel失败", e)
            }
        }
    }
}

注意事项

  • 永远通过系统API获取存储路径,不要硬编码,避免不同设备路径差异导致的问题。
  • 必须处理所有可能的异常(文件不存在、工作表/行/单元格为空等),防止空指针崩溃。
  • 用完Workbook和InputStream后务必关闭,避免资源泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 02:37:23