将 XSSFWorkbook 写入 zip 文件

问题描述 投票:0回答:4

我现在也遇到这个问题了。我想将此 XSSFWorkbook(工作簿)obj 中的 excel 文件写入 zip 文件,例如(example.zip,同时包含此 example.xlsx 文件)到远程服务器。 我尝试过以下操作但不起作用,它创建了一个文件夹,其中 zip 文件中有一些奇怪的文件

  XSSFWorkbook workbook = new XSSFWorkbook();
  //add some data
  Zipoutputstream zipstream=new Zipoutputstream(//destination outputstream);
  workbook.write(zipstream);

那么有谁知道这样做的正确方法是什么?预先感谢

ps workbook.write(fileoutputstream) 可以工作,但它只作为平面文件(例如 test.xlsx)写入本地磁盘,而不是根据我需要写入 zip 中。

java apache-poi zipoutputstream
4个回答
27
投票

ZipOutputStream
传递给
XSSFWorkbook.write
将导致流被工作簿劫持并关闭。这是因为
XSSFWorkbook
写入了
.xlsx
,它本身就是 xml 和其他文件的 zip 存档(您可以解压缩任何 .xslx 以查看其中的内容)。 如果您能够将 excel 文件放入内存中,我发现它效果很好:

ZipOutputStream zos = new ZipOutputStream(//destination outputstream);
zos.putNextEntry(new ZipEntry("AnExcelFile.xlsx"));
ByteArrayOutputStream bos = new ByteArrayOutputStream();
workbook.write(bos);
bos.writeTo(zos);
zos.closeEntry();
// Add other entries as needed
zos.close();

close
上调用
ByteArrayOutputStream
没有任何效果,仍然可以写入
zos


4
投票

您的

ZipOutputStream
错过了一些必要的电话。您需要为电子表格文件创建一个
ZipEntry
,然后将其写出来。你需要类似的东西

zipstream.putNextEntry(new ZipEntry("example.xlsx"));

那么你应该可以打电话

workbook.write(zipstream);

但是之后您需要在关闭流之前关闭条目。

zipstream.closeEntry();

请参阅 “从 Java 写入和读取 .Zip 文件”,了解如何使用 Java 的

ZipOutputStream
的详细信息。

另外,请注意 .xlsx 文件已经是压缩的 zip 文件,因此将其放入 .zip 文件中可能不会压缩太多。


3
投票

我的一位同事 M. Bunshaft 提出了一种与 Klugscheißer 类似的解决方案,但不需要使用 ByteArrayOutputStream,因此可以容纳更大的输出。 这个想法是子类 ZipOutputStream,重写 close() 方法,这样它就不会执行关闭。

public class UncloseableZipOutputStream extends ZipOutputStream
{
	OutputStream os;
	
	public UncloseableZipOutputStream( OutputStream os )
	{
		super(os);
	}
	
	@Override
	/** just flush but do not close */
	public void close() throws IOException
	{
		flush();
	}
	
	public void reallyClose() throws IOException
	{
		super.close();
	}
}

然后,只需按照使用 ZipOutputStream 的方式使用它即可。

UncloseableZipOutputStream zos = new UncloseableZipOutputStream(//destination outputstream);
zos.putNextEntry(new ZipEntry("AnExcelFile.xlsx"));
workbook.write(zos);
zos.closeEntry();      // now this will not cause a close of the stream
// Add other entries as needed
zos.reallyClose();


0
投票

这个方法对我有用: (输入是您拥有的文件的 byteArray)

public static byte[] zipBytes(String filename, byte[] input) throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ZipOutputStream zos = new ZipOutputStream(baos);
    ZipEntry entry = new ZipEntry(filename);
    entry.setSize(input.length);
    zos.putNextEntry(entry);
    zos.write(input);
    zos.closeEntry();
    zos.close();
    return baos.toByteArray();
}
© www.soinside.com 2019 - 2024. All rights reserved.