【问题标题】:write a XSSFWorkbook to a zip file将 XSSFWorkbook 写入 zip 文件
【发布时间】:2013-05-23 18:10:58
【问题描述】:

我现在有这个问题。我想将此 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,而不是我需要的压缩包内。

【问题讨论】:

    标签: java apache-poi zipoutputstream


    【解决方案1】:

    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();
    

    ByteArrayOutputStream 上调用close 无效,仍然可以写入zos

    【讨论】:

    • 这个解决方案可能需要一些清理和内联注释,因为它很难阅读。
    • 嘿@AttitudeL,很抱歉您发现这个答案难以阅读。您如何建议更改它以使其更清晰?
    • 您的解决方案很有魅力。由于多个流同时共存,我的建议是添加更多的 cmets。
    • 非常感谢,@Klugscheißer。我浪费了很多时间试图了解这些流的行为,而您的解决方案奏效了!!
    【解决方案2】:

    您在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 文件中可能不会压缩太多。

    【讨论】:

    • 嗨我的错误是我已经做过了,我实际上做的是 XSSFWorkbook workbook = new XSSFWorkbook(); //添加一些数据 Zipoutputstream zipstream=new Zipoutputstream(//destination outputstream); zipstream.putNextEntry(new ZipEntry("example.xlsx")); workbook.write(zipstream); zipstream.closeEntry();问题是 XSSFWorkbook.write 会自动关闭流。所以我把它改成 HSSFWorkbook。现在我有了文件,但我无法打开它,它说内容已损坏。有谁知道出了什么问题?谢谢。
    • *.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();

    【讨论】:

    • 我可以得到一个 zip 文件,其中 XLSX 文件的内容在同一级别,而不是在里面。
    • 实际上,您可以将ZipOutputStream 包装在FilterOutputStream 中,而不是编写自己的类。它只是起到传递的作用,并阻止stream instanceof ZipOutputStream 在 POI 代码中成功。
    猜你喜欢
    • 1970-01-01
    • 2011-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多