问题描述
Excel生成在生成流并且打包到.zip文件的时候,从网络上copy了一段代码,自己修改了部分,代码如下:
public void saveAsZip(String xlsxName, OutputStream output) throws ExcelException {
if (getWorkbook() == null || output == null) {
throw new ExcelException("Workbook is null or output is null");
}
InputStream inputStream;
try (ZipOutputStream zos = new ZipOutputStream(output);
FileOutputStream outTmp = new FileOutputStream(xlsxName);
) {
getWorkbook().write(outTmp);
outTmp.close();
inputStream = new FileInputStream(xlsxName);
zos.putNextEntry(new ZipEntry(xlsxName));
byte[] buffer = new byte[1024];
int len;
int i = 0;
while ((len = inputStream.read(buffer)) > 0) {
// zos.write(buffer, 0, len);
zos.write(buffer);
}
zos.closeEntry();
zos.close();
inputStream.close();
output.flush();
} catch (Exception e) {
throw new ExcelException(e);
}
}
但是生成的xlsx通过excel2010打开一直报错
解析
暂且不论上面的代码是否有更好的实现,这个代码的问题在于:
zos.write(buffer);
虽然,
write(buffer);
的内部是
write(buffer, 0, len)
实现的,但是,这里的第一个方法中的length默认为buffer.length,永远为1024,这是不对的,所以需要采用第二个实现,手动读取和指定长度length,否则会读取空byte到文件中,出现不可读的内容。
最终方案
- 原始的zipoutputStream流
public void saveAsZip(String xlsxName, OutputStream output) throws ExcelException {
if (getWorkbook() == null || output == null) {
throw new ExcelException("Workbook is null or output is null");
}
try (ZipOutputStream zos = new ZipOutputStream(output);
) {
zos.putNextEntry(new ZipEntry(xlsxName));
getWorkbook().write(zos);
zos.closeEntry();
output.flush();
} catch (Exception e) {
throw new ExcelException(e);
}
}
- apache的打包流:
public void saveAsZip(String xlsxName, OutputStream output) throws ExcelException {
if (getWorkbook() == null || output == null) {
throw new ExcelException("Workbook is null or output is null");
}
try (BufferedOutputStream bufferedOutput = new BufferedOutputStream(output);
ArchiveOutputStream archiveOutputStream = new ArchiveStreamFactory().createArchiveOutputStream(ArchiveStreamFactory.ZIP, bufferedOutput);
) {
ArchiveEntry archiveEntry = archiveOutputStream.createArchiveEntry(new File(xlsxName), xlsxName);
archiveOutputStream.putArchiveEntry(archiveEntry);
getWorkbook().write(archiveOutputStream);
archiveOutputStream.closeArchiveEntry();
archiveOutputStream.finish();
archiveOutputStream.flush();
} catch (Exception e) {
throw new ExcelException(e);
}
}
总结
关于流的读写由于平常用到的非常少,所以比较生疏,基础不牢,希望再用的时候能更加小心点。