将XSSFWorkbook写入zip文件

时间:2013-05-23 18:10:58

标签: java apache-poi zipoutputstream

我现在有这个问题。我想在此XSSFWorkbook(工作簿)obj中将excel文件保存写入zip文件,例如(包含此example.xlsx文件的example.zip)到远程服务器。    我试过以下但没有工作,它创建了一个包含zip文件中的奇怪文件的文件夹

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

所以有人知道这样做的正确方法是什么?提前致谢

ps workbook.write(fileoutputstream)有效,但它只能作为平面文件写入本地磁盘,例如test.xlsx而不是我需要的zip内部。

3 个答案:

答案 0 :(得分:17)

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

答案 1 :(得分:4)

您在ZipOutputStream上缺少必要的电话。您需要为电子表格文件创建ZipEntry,然后将其写出来。你需要像

这样的东西
zipstream.putNextEntry(new ZipEntry("example.xlsx"));

然后你应该可以打电话了

workbook.write(zipstream);

但在此之后,您需要在关闭流之前关闭该条目。

zipstream.closeEntry();

有关如何使用Java ZipOutputStream

的详细信息,请参阅"Write And Read .Zip File From Java"

另外,请注意.xlsx文件已经是压缩的zip文件,因此将其放在.zip文件中可能无法压缩它。

答案 2 :(得分:2)

我的一位同事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();