Mir*_* D. 6 java openxml apache-poi kotlin
我正在尝试使用 SXSSFWorkbook 从头开始编写 Excel 电子表格。
wb = SXSSFWorkbook(500)
wb.isCompressTempFiles = true
sh = streamingWorkbook.createSheet(t.getMessage("template.sheet.name"))
Run Code Online (Sandbox Code Playgroud)
一切都很好,但是当我调用最终代码时:
val out = FileOutputStream(localPath)
wb.write(out)
out.close()
// dispose of temporary files backing this workbook on disk
wb.dispose()
Run Code Online (Sandbox Code Playgroud)
我得到了一个巨大的 excel 文件,而不是我期待的压缩的 XLSX。我尝试手动压缩文件,从 120MB 的文件中我可以将其压缩到 9MB。那么我错过了什么?
使用:Kotlin 和
implementation group: 'org.apache.poi', name: 'poi-ooxml', version: '4.1.2' // For `.xlsx` files
Run Code Online (Sandbox Code Playgroud)
-- 更新 1
我的印象是 xlsx 本质上是包含 xml 数据的压缩文件[1]。通过 XSSFWorkbook 和 SXSSFWorkbook 输出的 POI 至少可以压缩 10 个数量级。 我已经使用这个简单的代码来演示:
fun main() {
val workbook = XSSFWorkbook()
writeRowsAndSave(workbook, "test.xlsx")
workbook.close()
val streamingWorkbook = SXSSFWorkbook(IN_MEMORY_ROWS_WINDOW_SIZE)
streamingWorkbook.isCompressTempFiles = true
writeRowsAndSave(streamingWorkbook, "test-streaming.xlsx")
streamingWorkbook.dispose()
}
private fun writeRowsAndSave(workbook: Workbook, fileName: String) {
val ROWS_COUNT = 2_000
val COLS_COUNT = 1_000
val sheet = workbook.createSheet("Test Sheet 1")
for (i in 1..ROWS_COUNT) {
val row = sheet.createRow(i)
println("Row $i")
for(j in 1..COLS_COUNT) {
row.createCell(j).setCellValue("Test $i")
}
}
FileOutputStream("./$fileName").use {
workbook.write(it)
}
}
Run Code Online (Sandbox Code Playgroud)
这会产生 5MB-每个文件,压缩后大约有 439KB (?!)。
SXSSFWorkbook
默认使用内联字符串而不是共享字符串表。这意味着SXSSFWorkbook
直接在工作表中写入文本,即使它是同一文本的多次。XSSFWorkbook
和 Excel 的 GUI 都使用共享字符串表,其中文本获取索引,相同的文本仅存储一次,然后在工作表中使用索引。但这不会对生成的文件大小产生那么大的影响*.xlsx
。
SXSSFWorkbook
以及创建的所有其他Office Open XML
格式文件apache poi
均使用org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream
. 它使用 deflate 作为压缩算法和Deflater.DEFAULT_COMPRESSION
默认压缩级别。人们可以覆盖protected ZipArchiveOutputStream createArchiveOutputStream(OutputStream out)
来SXSSFWorkbook
设置另一压缩级别。但这也不会对生成的文件大小产生那么大的影响*.xlsx
。
示例Java
代码:
import java.io.File;
import java.io.OutputStream;
import java.io.FileOutputStream;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.commons.compress.archivers.zip.Zip64Mode;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import java.util.zip.Deflater;
class CreateSXSSFDifferentCompression {
static SXSSFWorkbook createSXSSFWorkbook(int compressionLevel, int rowAccessWindowSize,
boolean compressTmpFiles, boolean useSharedStringsTable) {
SXSSFWorkbook workbook = null;
if (compressionLevel != Deflater.DEFAULT_COMPRESSION) {
workbook = new SXSSFWorkbook(null, rowAccessWindowSize, compressTmpFiles, useSharedStringsTable) {
protected ZipArchiveOutputStream createArchiveOutputStream(OutputStream out) {
ZipArchiveOutputStream zos = new ZipArchiveOutputStream(out);
zos.setUseZip64(Zip64Mode.AsNeeded);
zos.setLevel(compressionLevel);
return zos;
}
};
} else {
workbook = new SXSSFWorkbook(null, rowAccessWindowSize, compressTmpFiles, useSharedStringsTable);
}
return workbook;
}
public static void main(String[] args) throws Exception {
SXSSFWorkbook workbook = null;
// uses Deflater.DEFAULT_COMPRESSION and inline strings
//workbook = createSXSSFWorkbook(Deflater.DEFAULT_COMPRESSION, 500, true, false);
// uses Deflater.DEFAULT_COMPRESSION and shared strings table
//workbook = createSXSSFWorkbook(Deflater.DEFAULT_COMPRESSION, 500, true, true);
// uses Deflater.BEST_COMPRESSION and inline strings
workbook = createSXSSFWorkbook(Deflater.BEST_COMPRESSION, 500, true, false);
// uses Deflater.BEST_COMPRESSION and shared strings table
//workbook = createSXSSFWorkbook(Deflater.BEST_COMPRESSION, 500, true, true);
int ROWS_COUNT = 2000;
int COLS_COUNT = 1000;
Sheet sheet = workbook.createSheet("Test Sheet 1");
for (int i = 1 ; i <= ROWS_COUNT; i++) {
Row row = sheet.createRow(i);
//System.out.println("Row " + i);
for(int j = 1; j <= COLS_COUNT; j++) {
row.createCell(j).setCellValue("Test " + i);
}
}
FileOutputStream out = new FileOutputStream("./Excel.xlsx");
workbook.write(out);
out.close();
workbook.close();
workbook.dispose();
File file = new File("./Excel.xlsx");
System.out.println(file.length());
}
}
Run Code Online (Sandbox Code Playgroud)
这导致Excel.xlsx
文件大小为:
使用 Deflater.DEFAULT_COMPRESSION 和内联字符串时为 5,031,034 字节。
使用 Deflater.DEFAULT_COMPRESSION 和共享字符串表时为 4,972,663 字节。
使用 Deflater.BEST_COMPRESSION 和内联字符串时为 4,972,915 字节。
使用 Deflater.BEST_COMPRESSION 和共享字符串表时为 4,966,749 字节。
用过的:Java 12
,apache poi 4.1.2
,Ubuntu Linux
。
对于 2,000 行 x 1,000 列的电子表格,我既不会称其为巨大,也不认为不同设置的影响很大。
而且条目压缩得非常好。
如果您查看Excel.xlsx
ZIP 存档,您会发现xl/worksheets/sheet1.xml
使用内联字符串时未压缩的大小为 112,380,273 字节。未压缩的大小xl/sharedStrings.xml
为 138 字节,仅包含非常基本的 XML。
如果使用共享字符串表,则未压缩的大小xl/worksheets/sheet1.xml
为 68,377,273 字节,未压缩的大小xl/sharedStrings.xml
为 49,045 字节,包含 2,000 个条目。
如果Excel
它本身保存*.xlsx
文件,那么当内容相等时,它会创建具有大致相同文件大小的文件。所以Excel
它本身使用相同的压缩级别。
当然,当再次将文件存储到存档中时,可以*.xlsx
进一步压缩文件。但这并不是我们所期望的文件。 Excel.xlsx
*.zip
Excel
*.xlsx
Microsoft
指出Open XML 格式有哪些好处?:
压缩文件 文件会自动压缩,在某些情况下最多可缩小 75%。Open XML 格式使用 zip 压缩技术来存储文档,可以节省潜在的成本,因为它减少了存储文件所需的磁盘空间,并减少了通过电子邮件、网络和 Internet 发送文件所需的带宽。当您打开文件时,它会自动解压缩。当您保存文件时,它会自动再次压缩。您无需安装任何特殊的 zip 实用程序即可在 Office 中打开和关闭文件。
这里重要的部分是:
当您打开文件时,它会自动解压缩。当您保存文件时,它会自动再次压缩。
这意味着,如果apache poi
使用其他方法或压缩级别来压缩文件Microsoft Office
,则Microsoft Office
无法使用apache poi
已创建的文件来执行此操作。
因此,由于创建( ) 能够直接打开的apache poi
文件,因此它使用与( ) 相同的压缩方法和压缩级别。Excel
Microsoft Office
Excel
Microsoft Office
归档时间: |
|
查看次数: |
2505 次 |
最近记录: |