我现在有这个问题。我想在此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内部。
答案 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
。
另外,请注意.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();