Apache POI读取数据库存储的Docx文件报错NotOfficeXmlFileException求助
解决Apache POI读取Docx字节数组报错的问题
报错信息:
org.apache.poi.openxml4j.exceptions.NotOfficeXmlFileException: No valid entries or contents found, this is not a valid OOXML (Office Open XML) file
这个错误说明从数据库取出的字节数组不是有效的OOXML格式文件,以下是具体排查和解决步骤:
1. 验证字节数组的有效性
- 将数据库中的字节数组导出为本地文件,尝试用Microsoft Word或WPS打开:
- 如果打不开,说明文件在上传或存储过程中已损坏。
- 如果能打开,再用POI直接读取本地文件测试,排除代码逻辑问题。
- 代码中可添加格式校验:docx本质是ZIP压缩包,开头字节应为
PK\x03\x04,可在读取前检查:if (byteArray.length < 4 || byteArray[0] != 'P' || byteArray[1] != 'K' || byteArray[2] != 0x03 || byteArray[3] != 0x04) { throw new IllegalArgumentException("不是有效的Docx文件"); }
2. 检查上传与存储流程
- 上传环节:确认上传代码使用的是字节流读取文件,而非字符流。如果用
Reader类读取二进制文件,会导致字节编码错误,破坏文件结构。正确示例:// 上传时读取文件的正确方式 try (InputStream is = file.getInputStream()) { byte[] content = IOUtils.toByteArray(is); // 存储content到数据库 } - 数据库存储:确认存储字节数组的字段类型为二进制类型(如
BLOB、LONGBLOB),而非文本类型(TEXT、VARCHAR)。文本类型会将二进制数据按字符编码存储,导致数据损坏。
3. 优化代码的可靠性
- 使用
try-with-resources自动关闭流,避免手动关闭时的异常吞掉问题:public static KcDocx fromByteArray(byte[] byteArray) { try (ByteArrayInputStream inputStream = new ByteArrayInputStream(byteArray)) { XWPFDocument doc = new XWPFDocument(inputStream); return KcDocx.buildDoc(doc); } catch (IOException e) { log.warn("KcDocReaderBytes", e); throw new RuntimeException(e); } } - 添加日志记录字节数组长度,对比原始上传文件的大小。如果长度不一致,说明存储或读取时数据丢失。
4. 排查文件本身的类型问题
- 确认用户上传的文件是真的docx格式,而非将doc文件改后缀伪装的。doc格式需要用
HWPFDocument读取,而非XWPFDocument。可添加类型判断逻辑:// 简单区分doc和docx if (byteArray[0] == 'P' && byteArray[1] == 'K') { // docx格式,用XWPFDocument } else if (byteArray[0] == 0xD0 && byteArray[1] == 0xCF && byteArray[2] == 0x11 && byteArray[3] == 0xE0) { // doc格式,用HWPFDocument } else { throw new IllegalArgumentException("不支持的文档格式"); }
内容的提问来源于stack exchange,提问作者Nelvan Resi
相关产品推荐
相关产品推荐

