xlsx发现不可读取的内容,是否恢复此工作簿的内容?

问题描述

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到文件中,出现不可读的内容。

最终方案
  1. 原始的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);
        }
    }
  1. 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);
        }
    }
总结

关于流的读写由于平常用到的非常少,所以比较生疏,基础不牢,希望再用的时候能更加小心点。

在VBA (Visual Basic for Applications) 中,如果你想将多个Excel工作簿中的特定数据汇总到一个单独的工作表,你可以编写一个宏来完成这个任务。以下是一个简单的步骤描述: 1. **创建一个新的空白工作簿**:作为汇总的目标工作表。 2. **打开需要汇总的工作簿列表**:可以存储在一个数组或者集合里,每个元素代表一个工作簿路径。 3. **循环遍历工作簿列表**: - 使用 `Application.Workbooks.Open` 方法打开每个工作簿。 - 确定你要汇总的数据范围。例如,假设所有工作簿的特定数据都在A1区域。 4. **读取数据**: - 对于每个工作簿,获取对应数据区域的值,例如 `Worksheets("Sheet1").Range("A1")`。 5. **汇总数据**: - 将数据添加到目标工作簿的新行中。这通常涉及到选择目标单元格、设置值然后移动到下一行。比如使用 `.End(xlDown).Offset(1, 0)` 来找到下一个空行并输入数据。 6. **关闭不需要的工作簿**: - 当从当前工作簿读取完数据后,使用 `.Close SaveChanges:=False` 关闭它(`SaveChanges` 参数设为 False 可避免自动保存更改)。 7. **结束循环**: - 循环结束后,记得检查是否所有数据都已添加到目标工作表。 下面是一个基础的VBA示例代码片段,但这只是一个大概的框架,你需要根据实际情况调整变量名和具体的文件路径: ```vba Sub SummarizeData() Dim wbSource As Workbook Dim wsSource As Worksheet Dim wsTarget As Worksheet Dim DataRange As Range Dim SourceFile() As String ' 存储工作簿路径的数组 ' 初始化目标工作表和数据范围 Set wsTarget = ThisWorkbook.Sheets("Summary") Set DataRange = wsTarget.Range("A1") ' 设置工作簿路径数组 SourceFile = Array("C:\Path\To\Workbook1.xlsx", "C:\Path\To\Workbook2.xlsx") ' 替换为实际路径 For Each src In SourceFile Set wbSource = Workbooks.Open(src) ' 获取源工作簿数据区域 Set wsSource = wbSource.Sheets("Sheet1") DataRange.Value = wsSource.Range("A1").Value ' 这里假设数据在A1 ' 汇总数据到目标位置 ' 数据Range.Value = ... # 根据需要更新这里 ' 关闭工作簿 wbSource.Close SaveChanges := False Next src End Sub ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值