【项目实战】 Apache POI 导出 Excel 常见的23问题

【项目实战】 Apache POI 导出 Excel 常见的23问题

这里写图片描述

这个是即 《 Java中使用POI导出Excel 之 项目实战详细教程 》之后,需要注意的问题!

1、我使用 poi-ooxml-schemas jar,但是我的代码失败了,并且报“java.lang.NoClassDefFoundError:org / openxmlformats / schemas / * something *”异常 ?
要使用新的OOXML文件格式,POI需要包含由XMLBeans编译的文件格式XSD的jar 。这些XSD一旦编译成Java类,就可以在 org.openxmlformats.schemas命名空间中自动生成。
所有模式的完整jar都是ooxml-schemas-1.3.jar,目前大约是15mb。在较小的POI,ooxml-schemas 仅约4MB。后一个jar文件只包含通常使用的部分。
许多用户选择使用较小的 poi-ooxml-schema jar 来节省空间。然而,poi-ooxml-schema jar仅包含通常使用的XSD和类,如单元测试所标识。也许您可能会尝试使用不包含在最小poi-ooxml-schemas jar中的文件格式的一部分。在这种情况下,您应该切换到完整的ooxml-schemas-1.3.jar。长期来看,您也可能希望提交使用XSD的额外部分的新的单元测试,以便将来的poi-ooxml-schema jar将包含它们。
请注意,在历史上,使用了不同版本的ooxml-schemas

2、我的代码使用一些新功能,编译好但是当出现“MethodNotFoundException”或“IncompatibleClassChangeError” ?
您的类路径中几乎肯定有一个较旧版本的Apache POI。相当多的运行时和其他软件包会运送较旧版本的Apache POI,所以这是一个经常出现的问题。有些版本可能会使用一个就的版本,有些版本可能使用一整套旧的POI jar。
识别有争议的早期jar文件的最好方法是使用几行java代码。这些将加载一个Core POI类,一个OOXML类和一个Scratchpad类,并报告它们都来自哪里。

ClassLoader classloader =
   org.apache.poi.poifs.filesystem.POIFSFileSystem.class.getClassLoader();
URL res = classloader.getResource(
             “组织/阿帕奇/ POI / POIFS /文件系统/ POIFSFileSystem.class”);
String path = res.getPath();
System.out.println(“POI Core来自”+路径);

classloader = org.apache.poi.POIXMLDocument.class.getClassLoader();
res = classloader.getResource(“org / apache / poi / POIXMLDocument.class”);
path = res.getPath();
System.out.println(“POI OOXML来自”+路径);

classloader = org.apache.poi.hslf.usermodel.HSLFSlideShow.class.getClassLoader();
res = classloader.getResource(“org / apache / poi / hslf / usermodel / HSLFSlideShow.class”);
path = res.getPath();
System.out.println(“POI Scratchpad来自”+路径);

注意:以上的引用类的路径,不要搞错了哟!

3、我的代码使用暂存器,编译好了后,但是无法运行,并报“MethodNotFoundException” 样式的异常信息 ?
你的类路径上几乎肯定有一个旧版本。见前面的答案。

4、为什么读简单的纸张需要这么长时间?
您可能已启用日志记录。日志记录仅用于解剖样式调试。启用该功能将使性能降低至少100,当然日志记录有助于了解POI无法读取某些文件或开发POI本身的原因。重要的错误会抛出异常,这意味着你可能不需要日志记录。

5、什么是HSSF“事件模型”?
SS事件模型包是用于读取Excel文件的API,而不将整个电子表格加载到内存中。它确实需要用户的更多知识,但是将内存消耗减少了十倍以上。它基于与SAX结合的AWT事件模型。如果您需要只读访问权限,这是最好的方法。

6、为什么无法读取我使用Star Office 5.1创建的文档?
Star Office 5.1使用较旧的BIFF标准写入一些记录。这会导致仅支持BIFF8的POI的一些问题。

7、为什么每次尝试阅读我的电子表格时都会收到异常?
您的电子表格可能包含POI当前不支持的功能。如果遇到这种情况,请创建一个最简单的文件来演示问题并将其提交给 Bugzilla。

8.如何判断电子表格单元格是否包含日期?
Excel将日期存储为数字,因此确定单元格实际存储为日期的唯一方法是查看格式。在HSSFDateUtil中有一个帮助程序来检查这个。感谢Jason Hoffman提供的解决方案,解决方案如下:。

case HSSFCell.CELL_TYPE_NUMERIC:
         double d = cell.getNumericCellValue();
         //测试一个日期!
         if(HSSFDateUtil.isCellDateFormatted(cell)){
           //格式为M / D / YY
           cal.setTime(HSSFDateUtil.getJavaDate(d));
           cellText =
             (将String.valueOf(cal.get(Calendar.YEAR)))子串(2)。
           cellText = cal.get(Calendar.MONTH)+1 +“/”+
                      cal.get(Calendar.DAY_OF_MONTH)+“/”+
                      CELLTEXT;
         }

9、我正在尝试从一个servlet流式传输一个XLS文件,我有一些麻烦。有什么问题?
问题通常表现为屏幕上显示的垃圾字符。即使您设置了正确的MIME类型,问题仍然存在。
简短的答案是,如果您通过servlet流式传输,则不依赖于IE正确显示二进制文件类型。这个IE的每个小版本都有不同的bug。
大多数版本的IE的问题是它不使用HTTP响应的MIME类型来确定文件类型; 而是根据请求使用文件扩展名。
为确保在IE中正确打开文件,请将文件从您的servlet中写入您的Web根目录下的临时文件。然后向浏览器发送一个http响应,将客户端重定向到您的临时文件。(请注意,在这种情况下使用使用RequestDispatcher的服务器端重定向将无效)。
还请注意,当您请求使用外部处理程序打开的文档时,IE有时会向Web服务器发出两个请求。因此,如果您的生成过程很重,写入一个临时文件是有意义的,以便为静态文件发生多个请求。
这些都不是Excel特有的。当您尝试向IE客户端动态生成任何二进制文件时,也会出现同样的问题。例如,如果您使用FOP生成pdf文件 ,您将遇到许多相同的问题。

10、我想要将excel表格的单元格格式(单元格的数据格式)设置为###,###,###。####或###,###,###。 0000。是否可以使用POI?
可以的。您首先需要从工作簿中获取一个DataFormat对象,并使用所需的格式调用getFormat。举例如下:

Workbook wb = new HSSFWorkbook();
Sheet sheet = wb.createSheet(“format sheet”);
CellStyle;
DataFormat format = wb.createDataFormat();
cell;
Short rowNum = 0;
Short colNum = 0;

row = sheet.createRow(rowNum ++);
cell = row.createCell(colNum);
cell.setCellValue11111.25;
style = wb.createCellStyle();
style.setDataFormat(format.getFormat( “0.0”));
cell.setCellStyle(style);

row = sheet.createRow(rowNum ++);
cell = row.createCell(colNum);
cell.setCellValue11111.25;
style = wb.createCellStyle();
style.setDataFormat(format.getFormat( “#,## 0.0000”));
cell.setCellStyle(style);

FileOutputStream fileOut = new FileOutputStream(“workbook.xls”);
wb.write(FILEOUT);
fileOut.close();

11、我想要将excel表格的单元格格式(单元格的数据格式)设置为文本。是否可以使用POI?
可以的。这是Excel的内置格式,您可以使用格式字符串“@”从DataFormat对象获取。此外,字符串“文本”将别名此格式。

12、如何在合并的单元格周围添加边框?
在单元格正常放置的周围添加空白单元格,并为每个单元格单独设置边框。我们将来可能会加强HSSF,使之更容易。

13、在POI中创建工作簿时,我使用样式,但是Excel拒绝打开文件,并出现“Too many Styles”的问题?
您只需创建创建单元格的循环的外部OUTSIDE。
建议的写法:

HSSFWorkbook wb = new HSSFWorkbook();
 HSSFSheet sheet = wb.createSheet(“new sheet”);
 HSSFRow row = null;

 // Aqua Background
 HSSFCellStyle style = wb.createCellStyle();
 style.setFillBackgroundColor(HSSFColor.AQUA.index;
 style.setFillPattern(HSSFCellStyle.BIG_SPOTS);
 HSSFCell cell = row.createCell((short)1;
 cell.setCellValue( “X”);
 cell.setCellStyle(风格);

 //橙色“前景”,
 //前景是填充前景,而不是字体颜色。
 style = wb.createCellStyle();
 style.setFillForegroundColor(HSSFColor.ORANGE.index;
 style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);

 for(int x = 0; x <1000; x ++){

 //创建一行并放入一些单元格。行为0。
     row = sheet.createRow((short)k);

     for(int y = 0; y <100; y ++){
        cell = row.createCell((short)k);
        cell.setCellValue( “X”);
        cell.setCellStyle(style);
     }
 }

 //将输出写入文件
 FileOutputStream fileOut = new FileOutputStream(“workbook.xls”);
 wb.write(FILEOUT);
 fileOut.close();

不建议的写法:

HSSFWorkbook wb = new HSSFWorkbook();
 HSSFSheet sheet = wb.createSheet(“new sheet”);
 HSSFRow row = null;

 for(int x = 0; x <1000; x ++){
    // Aqua背景
    HSSFCellStyle style = wb.createCellStyle();
    style.setFillBackgroundColor(HSSFColor.AQUA.index;
    style.setFillPattern(HSSFCellStyle.BIG_SPOTS);
    HSSFCell cell = row.createCell((short)1;
    cell.setCellValue( “X”);
    cell.setCellStyle(风格);

    //橙色“前景”,
    //前景是填充前景,而不是字体颜色。
    style = wb.createCellStyle();
    style.setFillForegroundColor(HSSFColor.ORANGE.index;
    style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);

    //创建一行并放入一些单元格。行为0。
    row = sheet.createRow((short)k);

    for(int y = 0; y <100; y ++){
       cell = row.createCell((short)k);
       cell.setCellValue( “X”);
       cell.setCellStyle(风格);
    }
 }

 //将输出写入文件
 FileOutputStream fileOut = new FileOutputStream(“workbook.xls”);
 wb.write(FILEOUT);
 fileOut.close();

14、我认为POI使用的记忆太多了!我能做什么?
这一个出现了很多,但是经常的原因不是你最初想到的。所以,首先检查的是 - 问题的根源是什么?你的档案?你的代码?你的环境?还是Apache POI?
(如果你在这里,你可能认为它是Apache POI,但是它通常不是!一个中等的笔记本电脑,从一个站立的开始,体面但不是过多的堆大小,通常可以读取或写入一个100列的文件和几十万行,包括启动JVM的时间)。
Apache POI附带了几个程序和一些示例程序,可用于进行一些基本的性能检查。对于测试文件生成,使用的类是在示例包 SSPerformanceTest 中。运行具有写入类型(HSSF,XSSF或SXSSF)参数的SSPerformanceTest,数字行,列数以及文件是否应该保存。如果在3秒钟以内,HSSF和SXSSF中的50,000行和50列不能运行,而XSSF在10秒以内(理想情况下,所有都小于该值!),则问题出在您的环境中。
接下来,使用示例程序 ToCSV (viewvc)尝试使用HSSF或XSSF读取文件。相关的是 XLSX2CSV (viewvc),它使用.xlsx的SAX解析。对您的问题文件执行此操作,以及由相同大小的SSPerformanceTest生成的简单文件。如果这是缓慢的,那么可能会有一个Apache POI问题,如何处理文件(POI做出一些假设,可能并不总是正确的所有文件)。如果这些测试很快,那么任何性能问题都在你的代码中!

15、我似乎找不到OOXML CT ..类的来源,他们来自哪里?
Apache POI中的OOXML支持构建在文件格式XML模式之上,并使用XMLBeans将其编译为Java 。目前,使用XMLBeans 2.3完成编译,以实现与安装的最大兼容性。(您可以在XMLBeans 2.3运行时或任何更新版本的XMLBeans中使用生成的类。如果您当前正在使用XMLBeans 2.2或更早版本,则不幸的是您必须升级,但这并不常见)。
所有的org.openxmlformats.schemas.spreadsheetml.x2006 CT …类都是由XMLBean自动生成的。最终生成的Java进入ooxml-schemas-src jar,并将编译的版本转换为 ooxml-schemas jar。
完整的ooxml-schemas jar与Apache POI一起分发,还包含仅包含公共部分的切换poi-ooxml模式 jar。源jar不是正常分布与POI。然而,它可以从Maven Central获得 - 询问您最喜爱的Maven镜像的ooxml-schemas-src jar。或者,如果您下载POI源分发(或从SVN签出)并构建,Ant将自动下载规范XML模式,并编译它以生成源和二进制ooxml-schemas jar。

16、一个OLE2(“二进制”)文件给我的问题,但我无法分享。如何自行调查问题?
首先要尝试的是 从Microsoft 的二进制文件格式验证程序运行 文件,该文件将报告文件是否符合规范。如果您的输入文件没有,那么这可能很好地解释了为什么POI无法正确处理它。在这种情况下,您应该可以与生成文件进行整理,并将它们修复到那里。如果您的POI生成的文件被识别为有问题,并且您在 最新的代码库中,报告一个新的POI错误,并包括验证失败的详细信息。
另一件事情,特别是如果文件是有效的,但POI不符合预期,那么您正在使用的组件的POI开发工具。例如,HSSF具有org.apache.poi.hssf.dev.BiffViewer ,它允许您以POI的形式查看文件。这通常会允许您检查正在按预期读取的内容,并缩小问题记录和结构。

17、一个OOXML(“xml”)文件给我的问题,但我无法分享。如何自行调查问题?
目前还没有一个简单的验证器工具,因为基于OLE2的(二进制)文件格式,但检查文件的基本原理通常会更容易。
.xlsx,.docx和.pptx等文件实际上是一个具有特殊结构的XML文件的zip文件。诊断输入或输出文件问题的第一步可能是解压缩文件,并查看其中的XML。Office的较新版本通常会告诉您文件的哪个区域是有问题的,所以就很轻易的找到问题在哪里。
当报告错误时,已经包括整个文件,但是=您无法为问题区域添加XML代码段,并引用OOXML标准应包含哪些内容。

18、为什么我得到一个java.lang.NoClassDefFoundError:javax / xml / stream / XMLEventFactory.newFactory() 的错误信息 ?
此错误表示类XMLEventFactory不提供POI所依赖的功能。这可能有如下几个原因:
过期的xml-apis.jar,stax-apis.jar或xercesImpl.jar:
这些库是Java 5及更低版本所必需的,但实际上并不需要符合规范的Java 6实现,因此请尝试从类路径中删除这些库。如果不可能,请尝试升级到较新版本的这些jar文件。
运行IBM Java 6(可能作为WebSphere Application Server的一部分):
IBM Java 6不提供XML标准所需的所有接口,只有IBM Java 7似乎提供了正确的接口,因此请尝试升级JDK。
Sun / Oracle Java 6具有过时的补丁级别:
某些接口仅包含/修复了部分用于Java 6的补丁级别。请尝试使用最新的可用补丁级别运行,甚至更好地使用Java 7/8,其中该功能应该在所有案例。

19.我可以混合不同版本的 POI jar 吗?
否。不支持。
所有使用的POI jar 都必须来自相同的版本。不支持poi-3.11.jar和poi-ooxml-3.9.jar等组合,不能以不可预知的方式工作。
如果您不确定在运行时使用哪个POI jar 包,或您怀疑它可能不是您打算使用的POI jar,请参阅 此常见问题条目以了解诊断信息。如果您不确定需要什么POI jar 。

20、可以多线程访问/修改工作簿/文档/幻灯片吗?什么是Apache POI的多线程保证 ?
简而言之:在不同的线程中处理不同的文档对象将会起作用。在多个线程中访问相同的文档将无法正常工作。
这意味着工作簿/文档/幻灯片对象不会检查线程的安全性,但是任何全局保留的对象(如全局缓存或其他数据结构)都将被相应地防范多线程访问。
已经 讨论 了在不同线程中同时访问不同的工作簿。虽然这可能在某种程度上起作用,但是由于多线程问题通常仅在许多线程处于活动状态并且系统处于高负载状态(即在生产使用中)时长时间运行时才会出现,因此可能会非常难以跟踪错误!此外,在POI 的未来版本中也可能会出现这种情况,因为我们没有以这种方式专门测试库。

21、不同构造函数和写入方法的优缺点是什么?
在大多数UserModel类( POI Document 和 POI XMLDocument)中,您可以从只读文件,读写文件 或InputStream打开文档。你可以随时写出一个OutputStream,并增加一个File。
建议尽可能从文件中打开文档。这将永远是更快和更低的内存,然后使用InputStream,因为后者必须缓冲内存中的东西。
写入时,您可以使用OutputStream写入新文件,或覆盖现有文件(前提是尚未打开!)。在缓慢的链接/磁盘上,建议使用BufferedOutputStream进行包装。要这样写,请使用 write(OutputStream)。
要写入当前打开的文件(就地写入/替换),您需要从文件而不是InputStream打开文档。另外,您需要从读写模式中的文件打开,而不是只读模式。要写入当前打开的文件,支持它的格式(不是全部),请使用 write()。
你也可以写出一个新的文件。无论您如何打开文档,都可以使用此功能,并将创建/替换新文件。它比写入OutputStream更快,更低的内存。但是,您不能使用此替换当前打开的文件,只有当前未打开的文件。要写入新的/不同的文件,请使用 write(File)
HSSF和XSSF文档中也提供了更多信息 ,这些文档也适用于其他格式。
请注意,currenly(POI 3.15 beta 3),并不是所有的写入方法都可用于OOXML格式。

22、POI可以与OSGI一起使用吗?
从POI 3.16开始,有一个OSGI上下文类加载器处理的解决方法,即它使用有限类视图的实现来替换当前上下文类加载器。这将导致IllegalStateExceptions,因为xmlbeans在此缩减视图中找不到xml模式定义。解决方法是初始化POIXMLTypeLoader的类加载器委托,它默认为当前线程上下文类加载器。在任何其他OOXML相关调用之前,应进行初始化。示例中的类可以是任何类,它是poi-ooxml-schema或ooxml-schema的一部分:
POIXMLTypeLoader.setClassLoader(CTTable.class.getClassLoader());

23、Apache POI是否可以用Java 9进行编译/使用?
我们做了一些工作来验证使用Java 9的编译是否正常工作,并且所有单元测试都通过。所以Apache POI应该准备好与当前的Java 9发行版本一起使用。
注意:由于Java 9尚未终于发布,所以在最终版本中可能还会出现突破性变化,请小心使用!
对于编译Apache POI,您应该按照以下方法设置一些其他选项,以打开所需的某些模块,并取消设置不再受支持的某些编译器选项。

            #需要Ant版本> = 1.9.5,因为https://bz.apache.org/bugzilla/show_bug.cgi?id=58271
            Export ANT_HOME = / opt / apache / apache-ant / apache-ant-1.9.7
            export PATH = $ ANT_HOME / bin:$ PATH

            Export ANT_OPTS =“ -  Xmx1524m \
                --add-modules = java.xml.bind \
                --add-opens = java.xml / com.sun.org.apache.xerces.internal.util = ALL-UNNAMED \
                --add-打开= java.base / java.lang中= ALL-UNNAMED”

            ant\
            -Duser.language = en \
            -Duser.country = US \
            -Djava9addmods =  -  add-modules = java.xml.bind \
            -Djavadoc9addmods =  -  add-modules = java.xml.bind \
            -Djava9addmodsvalue = -Dsun.reflect.debugModuleAccessChecks = true \
            -Djava9addopens1 =  -  add-opens = java.xml / com.sun.org.apache.xerces.internal.util = ALL-UNNAMED \
            -Djava9addopens2 =  -  add-opens = java.base / java.io = ALL-UNNAMED \
            -Djava9addopens3 =  -  add-opens = java.base / java.nio = ALL-UNNAMED \
            -Djava9addopens4 =  -  add-opens = java.base / java.lang = ALL-UNNAMED \
            -Djava9addopens5 =  -  add-opens = java.base / jdk.internal.ref = ALL-UNNAMED \
            -Djava.locale.providers = JRE,CLDR \
            -Dcoverage.enabled = true \
            测试所有

本博文文来自 Apache POI 官网,如果期间还遇到其它问题,可以给我留言,一起探讨。
也希望大家多多关注CSND的IT社区。

你可能感兴趣的:(Apache_POI)