当前位置: 首页 > 知识库问答 >
问题:

为什么 POI 需要花费如此多的内存来处理 xlsx

郑宏朗
2023-03-14

我有一个xlsx文件,大小为90MB,不是很大。

首先,我使用XSSFWorkbook来阅读它,我得到了一个OutOfMemory错误。好吧,我改为使用XSSF和SAX(事件API)来读取。

当我尝试编写xlsx文件时,文档 https://poi.apache.org/components/spreadsheet/how-to.html#sxssf 告诉“SXSSF刷新临时文件(每工作表一个临时文件)中的工作表数据,这些临时文件的大小可以增长到一个非常大的值。例如,对于 20 MB 的 csv 数据,临时 xml 的大小将超过 1 GB。

为什么它需要花费如此多的存储?

共有1个答案

袁安志
2023-03-14

版本 2007 及更高版本的所有 Microsoft Office 文件都是 Office Open XML 文件。这是 ZIP 存档,其中包含 XML 文件和特殊目录结构中的其他嵌入文件。

让我们举个例子:

CSV:

Name, Class, Amount
Name1, Class1, 1234.56

长度:43个字符。

最小工作表-XML:

<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
 <dimension ref="A1"/>
 <sheetViews>
  <sheetView workbookViewId="0" tabSelected="true"/>
 </sheetViews>
 <sheetFormatPr defaultRowHeight="15.0"/>
 <sheetData>
  <row r="1">
   <c r="A1" t="inlineStr">
    <is>
     <t>Name</t>
    </is>
   </c>
   <c r="B1" t="inlineStr">
    <is>
     <t>Class</t>
    </is>
   </c>
   <c r="c1" t="inlineStr">
    <is>
     <t>Amount</t>
    </is>
   </c>
  </row>
  <row r="2">
   <c r="A2" t="inlineStr">
    <is>
     <t>Name1</t>
    </is>
   </c>
   <c r="B2" t="inlineStr">
    <is>
     <t>Class1</t>
    </is>
   </c>
   <c r="B2" t="n">
    <v>1234.56</v>
   </c>
  </row>
 </sheetData>
 <pageMargins bottom="0.75" footer="0.3" header="0.3" left="0.7" right="0.7" top="0.75"/>
</worksheet>

长度:854个字符。

因此,使用的文本字节的绝对数量要高出20倍。这只是一个非常简单的例子。

每个单元格值的最小开销为56个字符:

 <c r=".." t="inlineStr">
  <is>
   <t></t>
  </is>
 </c>

与CSV数据相比。

产生的< code>*。xlsx文件是一个ZIP文件,它使用了压缩。但是,默认情况下,临时表文件不被压缩,以节省时间和随机存取存储器。但是您链接的资源完全声明:

SXSSF刷新临时文件(每个工作表一个临时文件)中的工作表数据,这些临时文件的大小可能会变得非常大。例如,对于一个20 MB的csv数据,temp xml的大小超过了千兆字节。如果临时文件的大小是个问题,您可以告诉SXSSF使用gzip压缩:

SXSSFWorkbook wb = new SXSSFWorkbook();
wb.setCompressTempFiles(true); // temp files will be gzipped

因此,当临时文件的大小是个问题时,它提供了一个解决方案。当然,这需要时间和随机存取存储器。

但是,如前所述,使用XML作为文件格式有其自身的成本。

当谈到为什么Excel使用XML那么用于*.xlsx时,答案很复杂,可能是基于意见的。

这比纯文本CSV有优势。例如,不同的数据类型可以存储得更节省。数据格式的存储是可能的。存储单元格样式和格式也是可能的...除了CSV永远无法存储的内容:绘图、图片、图表、单元格注释,...

但这也适用于< code>*使用的以前的二进制BIFF格式。xls。因为二进制格式更接近于二进制计算,所以内存的使用要少得多。

但是所有的二进制Office格式都是闭源的,微软面临着发布文件格式定义的压力。XML是当时办公文件最常用的格式。例如,已经有了OpenOffice。因此...

OpenOffice使用OpenDocument文件格式。这也是包含XML文件和其他嵌入文件的ZIP存档,它们位于一个特殊的目录结构中。但是内部结构和使用的XML模式与微软的< code>Office Open XML不同。

 类似资料:
  • (英语不是我的第一语言,所以请原谅任何错误) 我使用SparkSQL从hive表中读取4.7TB的数据,并执行计数操作。做那件事大约需要1.6小时。而直接从HDFS txt文件读取和执行计数,只需要10分钟。这两个作业使用相同的资源和并行性。为什么RDD计数需要这么多时间? 配置单元表大约有30万列,序列化可能代价高昂。我检查了spark UI,每个任务读取大约240MB的数据,执行大约需要3.6

  • 问题内容: 要编译此代码,我可以: 将我的通话置于try / catch块中,或 已经声明它可以抛出一个。 为什么我必须这样做? (示例代码来自Kathy Sierra的SCJP书 。) 我知道引发的异常是已检查的异常,因此我必须处理它,但是在什么情况下需要引发此异常? 问题答案: 如果以一种可以引发检查异常的方式声明方法(不是的子类),则调用该方法的代码必须在一个块中调用它,否则调用者方法必须声

  • 根据我们的实验,我们发现当状态变成超过一百万个对象时,有状态的Spark Streaming内部处理成本会花费大量时间。因此,延迟会受到影响,因为我们必须增加批处理间隔以避免不稳定的行为(处理时间 它与我们应用程序的细节无关,因为它可以通过下面的代码复制。 Spark内部处理/基础架构成本到底是什么,需要这么多时间来处理用户状态?除了简单地增加批处理间隔之外,还有什么选项可以减少流转时长吗? 我们

  • 有人能正确解释事件时间戳和水印吗。我从文件中理解了,但不太清楚。一个真实的例子或外行的定义会有所帮助。此外,如果可能,请给出一个示例(以及一些可以解释它的代码片段)。提前感谢

  • 问题内容: 在64位系统上,Python中的整数占用24个字节。这是C语言中64位整数所需内存的3倍。现在,我知道这是因为Python整数是对象。但是,额外的内存又有什么用呢?我有我的猜测,但肯定会很高兴。 问题答案: 请记住,Python类型没有C那样有限的范围。唯一的限制是可用内存。 内存用于存储值,整数存储的当前大小(存储大小可变以支持任意大小)以及标准的Python对象簿记(对相关对象的引

  • 我已经读了很多关于内存对齐的书,但我不明白,我知道这是一种重要的方法,要编写高效的代码,你必须牢记这一点。但我感到困惑。