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

Android端使用Apache POI打开.xlsx文件抛出异常求助

Android端POI读取.xlsx文件抛出SAXNotRecognizedException异常问题

问题现象

  • Android应用开发中,通过Intent.ACTION_OPEN_DOCUMENT拉起系统文件选择器选取Excel文件,获取返回的文件Uri后,通过ContentResolver打开文件输入流传入WorkbookFactory.create(inputStream)读取文件:
    • .xls格式文件可正常解析,无异常
    • .xlsx格式文件解析时直接抛出SAXNotRecognizedException、POIXMLException崩溃

异常日志

D/test: uri: content://com.android.externalstorage.documents/document/0C19-391B%3Atest.xlsx

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.myexceloperatesample, PID: 20662
    org.apache.poi.ooxml.POIXMLException: http://xml.org/sax/properties/declaration-handler
        at org.apache.poi.ooxml.POIXMLFactory.createDocumentPart(POIXMLFactory.java:66)
        at org.apache.poi.ooxml.POIXMLDocumentPart.read(POIXMLDocumentPart.java:657)
        at org.apache.poi.ooxml.POIXMLDocument.load(POIXMLDocument.java:180)
        at org.apache.poi.xssf.usermodel.XSSFWorkbook.<init>(XSSFWorkbook.java:286)
        at org.apache.poi.xssf.usermodel.XSSFWorkbookFactory.createWorkbook(XSSFWorkbookFactory.java:88)
        at org.apache.poi.xssf.usermodel.XSSFWorkbookFactory.createWorkbook(XSSFWorkbookFactory.java:135)
        at java.lang.reflect.Method.invoke(Native Method)
        at org.apache.poi.ss.usermodel.WorkbookFactory.createWorkbook(WorkbookFactory.java:339)
        at org.apache.poi.ss.usermodel.WorkbookFactory.createXSSFWorkbook(WorkbookFactory.java:314)
        at org.apache.poi.ss.usermodel.WorkbookFactory.create(WorkbookFactory.java:232)
        at org.apache.poi.ss.usermodel.WorkbookFactory.create(WorkbookFactory.java:198)
        at com.example.myexceloperatesample.utility.ExcelDataProcessor.getWorkbook(ExcelDataProcessor.kt:67)
        at com.example.myexceloperatesample.utility.ExcelDataProcessor.execute(ExcelDataProcessor.kt:36)
        at com.example.myexceloperatesample.list.ListCheckFragment.startForResult$lambda-0(ListCheckFragment.kt:45)
        at com.example.myexceloperatesample.list.ListCheckFragment.$r8$lambda$mjTpkbLSgZW3CDTcSV4joyxwpyA(Unknown Source:0)
        at com.example.myexceloperatesample.list.ListCheckFragment$$ExternalSyntheticLambda2.onActivityResult(Unknown Source:4)
        at androidx.activity.result.ActivityResultRegistry$1.onStateChanged(ActivityResultRegistry.java:148)
        at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.java:360)
        at androidx.lifecycle.LifecycleRegistry.forwardPass(LifecycleRegistry.java:271)
        at androidx.lifecycle.LifecycleRegistry.sync(LifecycleRegistry.java:313)
        at androidx.lifecycle.LifecycleRegistry.moveToState(LifecycleRegistry.java:151)
        at androidx.lifecycle.LifecycleRegistry.handleLifecycleEvent(LifecycleRegistry.java:134)
        at androidx.fragment.app.Fragment.performStart(Fragment.java:3058)
        at androidx.fragment.app.FragmentStateManager.start(FragmentStateManager.java:587)
        at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:279)
        at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:113)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1374)
        at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2841)
        at androidx.fragment.app.FragmentManager.dispatchStart(FragmentManager.java:2791)
        at androidx.fragment.app.Fragment.performStart(Fragment.java:3062)
        at androidx.fragment.app.FragmentStateManager.start(FragmentStateManager.java:587)
        at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:279)
        at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:113)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1374)
        at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2841)
        at androidx.fragment.app.FragmentManager.dispatchStart(FragmentManager.java:2791)
        at androidx.fragment.app.FragmentController.dispatchStart(FragmentController.java:273)
        at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:486)
        at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:246)
        at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1435)
        at android.app.Activity.performStart(Activity.java:8018)
        at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3475)
        at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:221)
        at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:201)
E/AndroidRuntime:     at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:173)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7656)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
     Caused by: java.lang.reflect.InvocationTargetException
        at java.lang.reflect.Constructor.newInstance0(Native Method)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
        at org.apache.poi.xssf.usermodel.XSSFFactory.createDocumentPart(XSSFFactory.java:56)
        at org.apache.poi.ooxml.POIXMLFactory.createDocumentPart(POIXMLFactory.java:63)
            ... 52 more
     Caused by: java.lang.RuntimeException: http://xml.org/sax/properties/declaration-handler
        at org.apache.xmlbeans.impl.store.Locale$SaxLoader.<init>(Locale.java:3389)
        at org.apache.xmlbeans.impl.store.Locale$XmlReaderSaxLoader.<init>(Locale.java:3076)
        at org.apache.xmlbeans.impl.store.Locale.getSaxLoader(Locale.java:3061)
        at org.apache.xmlbeans.impl.store.Locale.parseToXmlObject(Locale.java:1272)
        at org.apache.xmlbeans.impl.store.Locale.parseToXmlObject(Locale.java:1259)
        at org.apache.xmlbeans.impl.schema.SchemaTypeLoaderBase.parse(SchemaTypeLoaderBase.java:345)
        at org.openxmlformats.schemas.drawingml.x2006.main.ThemeDocument$Factory.parse(Unknown Source:6)
        at org.apache.poi.xssf.model.ThemesTable.<init>(ThemesTable.java:86)
            ... 56 more
     Caused by: org.xml.sax.SAXNotRecognizedException: http://xml.org/sax/properties/declaration-handler
        at org.apache.harmony.xml.ExpatReader.setProperty(ExpatReader.java:170)
        at org.apache.xmlbeans.impl.store.Locale$SaxLoader.<init>(Locale.java:3383)
            ... 63 more

问题复现代码

Excel解析逻辑

class ExcelDataProcessor(
    private val activity: FragmentActivity,
    private val result: ActivityResult,
    private val excelViewModel: ExcelViewModel
) {
    fun execute() {
        val uri = result.data!!.data
        val workbook: Workbook = getWorkbook(uri!!)
    }

    private fun getWorkbook(uri: Uri): Workbook{
        return if (uri.toString().endsWith(".xlsx")) {
            Log.d("test", "uri: $uri")
            val inputStream = activity.contentResolver?.openInputStream(uri)
            WorkbookFactory.create(inputStream)

        } else {
            val inputStream = activity.contentResolver?.openInputStream(uri)
            WorkbookFactory.create(inputStream)
        }
    }
}

文件选择逻辑

class ListCheckFragment : Fragment() {

    private var _binding : FragmentListCheckBinding? = null
    private val binding get() = _binding!!

    private val excelViewModel: ExcelViewModel by activityViewModels()

    private val startForResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()){
            result: ActivityResult? ->
        if (result?.resultCode == RESULT_OK) {
            ExcelDataProcessor(requireActivity(), result, excelViewModel)
                .execute()
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?,
    ): View {
        _binding = FragmentListCheckBinding.inflate(inflater,container,false)

        binding.fileImportButton.setOnClickListener { openFileProvider() }

        return binding.root
    }

    private fun openFileProvider() {
        val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
            addCategory(Intent.CATEGORY_OPENABLE)
            type = "*/*"
            putExtra(Intent.EXTRA_MIME_TYPES,
                arrayOf(
                "application/vnd.ms-excel",
                "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
                )
            )
        }
        startForResult.launch(intent, null)
    }
}

项目依赖配置

android {
    compileSdk 32

    defaultConfig {
        applicationId "com.example.myexceloperatesample"
        minSdk 26
        targetSdk 32
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }

    viewBinding {
        enabled = true
    }

    dataBinding {
        enabled = true
    }

}

dependencies {

    implementation 'androidx.core:core-ktx:1.7.0'
    implementation 'androidx.appcompat:appcompat:1.4.1'
    implementation 'com.google.android.material:material:1.6.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
    implementation 'androidx.navigation:navigation-fragment-ktx:2.4.2'
    implementation 'androidx.navigation:navigation-ui-ktx:2.4.2'

    implementation "org.apache.poi:poi:4.0.1"
    implementation "org.apache.poi:poi-ooxml:4.0.1"
    implementation 'org.apache.xmlbeans:xmlbeans:3.0.2'
    implementation "org.apache.poi:poi-ooxml-schemas:1.4"
    implementation 'xerces:xercesImpl:2.8.0'
    implementation 'com.fasterxml:aalto-xml:1.2.2'
    implementation files('libs/javax.xml.stream-3.0.1.jar')
    implementation files('libs/dom4j-2.0.3.jar')
    kapt 'org.apache.logging.log4j:log4j-core:2.17.2'
}

问题根因

  1. 格式解析逻辑差异:.xls是BIFF二进制格式,POI解析时不需要XML解析组件;.xlsx是OOXML压缩包格式,内部所有结构都是XML文件,解析时依赖xmlbeans组件调用SAX解析器处理XML内容。
  2. 系统解析器能力限制:Android系统内置的org.apache.harmony.xml.ExpatReader SAX解析器不支持http://xml.org/sax/properties/declaration-handler属性,xmlbeans初始化SAX加载器时尝试设置该属性直接抛出异常。
  3. 依赖冲突导致兼容方案失效:现有依赖存在版本不匹配问题:poi-ooxml-schemas:1.4是POI 1.x版本的组件,和当前引入的POI 4.0.1完全不兼容;额外引入的xerces、aalto-xml、手动导入的jar包没有被设置为默认SAX驱动,类加载时优先加载了系统内置的ExpatReader,导致兼容的解析器没有生效。

修复方案

  • 清理冗余冲突依赖:删除所有POI相关的旧依赖,包括poi、poi-ooxml、xmlbeans、poi-ooxml-schemas、xerces、aalto-xml、手动导入的javax.xml.stream、dom4j、log4j相关kapt依赖,替换为适配Android平台的POI依赖组合,从根源解决SAX解析器兼容问题:
    implementation 'org.apache.poi:poi:5.2.3'
    implementation 'org.apache.poi:poi-ooxml:5.2.3'
    implementation 'com.github.SUPERCILEX.poi-android:poi:5.2.3'
    
    使用上述依赖需要在项目根目录的仓库配置中添加jitpack仓库源。
  • 优化文件读取逻辑:删除无意义的格式判断分支,使用use扩展函数自动关闭输入流,避免资源泄漏:
    private fun getWorkbook(uri: Uri): Workbook {
        return activity.contentResolver?.openInputStream(uri)?.use { inputStream ->
            WorkbookFactory.create(inputStream)
        } ?: throw IllegalStateException("无法打开目标文件输入流")
    }
    
  • 备选方案(不引入第三方适配包):如果不想使用适配版依赖,可以保留和POI版本匹配的xerces依赖,在Application的onCreate生命周期中手动指定默认SAX驱动,强制xmlbeans使用支持对应属性的解析器,跳过系统内置的ExpatReader:
    override fun onCreate() {
        super.onCreate()
        System.setProperty("org.xml.sax.driver", "org.apache.xerces.parsers.SAXParser")
    }
    
    该方案需要严格匹配xerces和POI的版本,否则会出现其他类冲突问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 21:48:48