前段时间有一个客户遇到了一件很奇怪的事情,他在使用程序解析一批word文件时 , 程序在运行一段时间后总是会自动中断 , 他查看了导致中断的word文档,发现也能正常打开,当他把文件另存为后,再运行程序发现程序就可以正常往下运行了 。他感觉很奇怪,就找我来帮他分析一下原因 。
一、问题分析(以下日志和代码均是重现问题后输出的)
首先登录服务器,找到程序的运行日志,打开当天运行的日志文件,查看是否有错误日志 , 果然发现了错误日志,具体内容如下:java.lang.IllegalArgumentException: The document is really a OOXML fileat org.apache.poi.hwpf.HWPFDocumentCore.verifyAndBuildPOIFS(HWPFDocumentCore.java:123)at org.apache.poi.hwpf.extractor.WordExtractor.(WordExtractor.java:51)at com.file.util.readword.redWordText(Test.java:25)at com.file.util.readword.main(Test.java:77)
根据错误日志不难分析出是解析doc文件报错了,根据错误日志可以直接定位到错位代码所在位置,通过反编译工具可以查看它的源码,源码具体如下(看到下面的代码 , 小伙伴们是否确定了问题的原因了?):
public static String redWordText(String filePath){File file=new File(filePath);String fileName=file.getName();//获取文件名String suffix = fileName.substring(fileName.indexOf("."), fileName.length());//获取文件后缀String text="";InputStream is = null;try {is = new FileInputStream(filePath);if (StringUtils.equals(suffix, ".doc")) {// 解析doc文件WordExtractor ex = new WordExtractor(is);text = ex.getText();ex.close();} else if (StringUtils.equals(suffix, ".docx")) {// 解析docx文件XWPFDocument doc = new XWPFDocument(is);XWPFWordExtractor extractor = new XWPFWordExtractor(doc);text = extractor.getText();extractor.close();}} catch (Exception e) {e.printStackTrace();}finally {if (is != null) {try {is.close();} catch (IOException e) {e.printStackTrace();}}}return text;}
当我看到源码后,基本确定了问题出现的原因 。
二、原因分析
客户收集上来的文件,渠道是多样的,有些docx文件的后缀被强制修改成了doc后缀,这些修改后的文件还是可以正常打开的 。当使用StringUtils.equals(suffix, ".doc")这种直接判断后缀的方式来判断文件类型是返回true的,导致docx文件使用了doc的解析方式 , 所以报错了 。三、解决办法
针对上面的问题可以使用FileMagic.valueOf(is) == FileMagic.OLE2来判断是否是doc格式文件,具体实现代码如下:public static String redWordText1(String filePath){String text = "";InputStream is = null;try {is = new FileInputStream(filePath);if (FileMagic.valueOf(is) == FileMagic.OLE2) {WordExtractor ex = new WordExtractor(is);text = ex.getText();ex.close();} else if (FileMagic.valueOf(is) == FileMagic.OOXML) {XWPFDocument doc = new XWPFDocument(is);XWPFWordExtractor extractor = new XWPFWordExtractor(doc);text = extractor.getText();extractor.close();}} catch (Exception e) {e.printStackTrace();} finally {if (is != null) {try {is.close();} catch (IOException e) {e.printStackTrace();}}}return text;}