请选择 进入手机版 | 继续访问电脑版
 找回密码
 立即注册

QQ登录

只需一步,快速开始

Kosen
金牌服务用户   /  发表于:2025-5-7 15:10  /   查看:98  /  回复:15
本帖最后由 Matthew.Xue 于 2025-5-12 10:09 编辑


调研编号:GCEXCEL-11768
我们现在的场景抽象出来大概是这样,我们通过GCExcel写好一个完整的工作簿,但我们导出的时候,只想导出那些包含公式计算的报表页,纯数据页不导出。我们现在的解决方案是:新建一个Workbook对象,通过SerializationOptions.setIgnoreFormula(true)再复制sheet过来。但是目前发现带有数据透视表的sheet页无法复制会报空指针。所以我这边有两个问题:

1. 带数据透视表的sheet页是否可以复制(毕竟他的数据源可能在新的tmpWorkbook不存在)?
2. 如果可以复制,具体要怎么做?

下面是我们的一个Demo,Data是纯数据页,导出时候想只保留Formula和PivotTable两个sheet页的具体值。

  1. String fileName = "790f6f4ad0d74100b1c85aae4ebc415c_tmp";
  2.         String filePath = "D:\\MyDownloads\" + fileName + ".sjs";
  3.         Workbook workbook = new Workbook();
  4.         workbook.open(filePath, OpenFileFormat.Sjs);
  5.         // 把报表页固化复制到一个临时工作簿中
  6.         Workbook tmpWorkbook = new Workbook();
  7.         SerializationOptions options = new SerializationOptions();
  8.         options.setIgnoreFormula(true);
  9.         // 复制公式数据
  10.         IWorksheet formula = workbook.getWorksheets().get("Formula");
  11.         IWorksheet tmpFormula = tmpWorkbook.getWorksheets().get(0);
  12.         tmpFormula.fromJson(formula.toJson(options));
  13.         // 复制透视表
  14.         IWorksheet pivotTable = workbook.getWorksheets().get("PivotTable");
  15.         IWorksheet tmpPivotTable = tmpWorkbook.getWorksheets().add();
  16.         tmpPivotTable.fromJson(pivotTable.toJson(options));
  17.         tmpWorkbook.save( "D:\\MyDownloads\" + fileName + ".xlsx");
复制代码



当然如果GCExcel本身有其他更灵活的实现方式,也可以告知我一下~

790f6f4ad0d74100b1c85aae4ebc415c_tmp.sjs

9.33 KB, 下载次数: 2

15 个回复

倒序浏览
Matthew.Xue
超级版主   /  发表于:2025-5-7 16:36:42
沙发
您好,最简单的方式是拷贝一个workbook,并删除Data表,但是考虑到您业务场景中Data表可能很大,拷贝会导致内存占用急剧升高,所以给您提供另外一种方式,您可以自行测试:

  1. Workbook workbook = new Workbook();
  2. workbook.open("sf.sjs", OpenFileFormat.Sjs);
  3. // 把报表页固化复制到一个临时工作簿中
  4. Workbook tmpWorkbook = new Workbook();
  5. SerializationOptions options = new SerializationOptions();
  6. options.setIgnoreFormula(true);
  7. // 复制公式数据
  8. IWorksheet formula = workbook.getWorksheets().get("Formula");
  9. IWorksheet tmpFormula = tmpWorkbook.getWorksheets().get(0);
  10. tmpFormula.fromJson(formula.toJson(options));
  11. // 复制透视表
  12. IWorksheet pivotTable = workbook.getWorksheets().get("PivotTable");
  13. pivotTable.copy(tmpWorkbook); // 注意,传入的参数是tmpWorkbook,而非worksheet
  14. tmpWorkbook.save( "result.xlsx");
复制代码
其中复制透视表的核心逻辑在于pivotTable.copy(tmpWorkbook),经过我的测试,result.xlsx是正常的,且Data表也没有被拷贝进来:
image.png172089537.png
回复 使用道具 举报
Kosen
金牌服务用户   /  发表于:2025-5-7 18:06:53
板凳
Matthew.Xue 发表于 2025-5-7 16:36
您好,最简单的方式是拷贝一个workbook,并删除Data表,但是考虑到您业务场景中Data表可能很大,拷贝会导致 ...

试了下,纯透视表可以复制成功,但是如果一个sheet里又有透视表又有公式,copy的话还是没办法只复制值,会带着公式一起,然后就报错#REF!
回复 使用道具 举报
Lewis
初级会员   /  发表于:2025-5-8 08:50:15
地板
或者试一下先把所有内容不带公式导出,然后重新打开这个工作簿,把Data页删除,再次导出,是不是可以满足你的需求:
  1. Workbook wb = new Workbook();
  2.         wb.open("E:\\Downloads\\790f6f4ad0d74100b1c85aae4ebc415c_tmp.sjs");
  3.         XlsxSaveOptions  saveOptions = new XlsxSaveOptions();
  4.         saveOptions.setIgnoreFormulas(true);
  5.         wb.save("F:\\out2.xlsx", saveOptions);
  6.         Workbook newWorkbook = new Workbook();
  7.         newWorkbook.open("F:\\out2.xlsx");
  8.         newWorkbook.getWorksheets().get("Data").delete();
  9.         newWorkbook.save("F:\\out3.xlsx");
复制代码


评分

参与人数 1满意度 +5 收起 理由
Kosen + 5

查看全部评分

回复 使用道具 举报
Matthew.Xue
超级版主   /  发表于:2025-5-8 09:51:26
5#
本帖最后由 Matthew.Xue 于 2025-5-8 09:58 编辑
Kosen 发表于 2025-5-7 18:06
试了下,纯透视表可以复制成功,但是如果一个sheet里又有透视表又有公式,copy的话还是没办法只复制值, ...

确实存在这种情况,但是也比较好解决,在copy完成之后,遍历pivotTable,获取所有单元格的formula,如果有formula,则获取该单元格的值,并且删除tmpPivotTable中相同坐标单元格的formula,设置为值即可。
  1. IWorksheet tmpPivotTable = tmpWorkbook.getWorksheets().get("PivotTable");
  2. IRange usedRange = pivotTable.getUsedRange();
  3. for(int r = usedRange.getRow();r<usedRange.getRow()+usedRange.getRowCount();r++) {
  4.     for(int c = usedRange.getColumn();c<usedRange.getColumn()+usedRange.getColumnCount();c++) {
  5.         String f = pivotTable.getRange(r,c).getFormula();
  6.         if(!f.isEmpty()) {
  7.             System.out.println(r+","+c+","+f);
  8.             Object value = pivotTable.getRange(r,c).getValue();
  9.             tmpPivotTable.getRange(r,c).setFormula(null);
  10.             tmpPivotTable.getRange(r,c).setValue(value);
  11.         }
  12.     }
复制代码


回复 使用道具 举报
Kosen
金牌服务用户   /  发表于:2025-5-8 11:43:20
6#
Matthew.Xue 发表于 2025-5-8 09:51
确实存在这种情况,但是也比较好解决,在copy完成之后,遍历pivotTable,获取所有单元格的formula,如果 ...

好的谢谢!不过目前我采用了楼上Lewis的方案,相对实现容易一点。可以帮忙也评估下这个方案有没有啥问题。另外我也挺好奇为啥带透视表的sheet在fromJson时候会报空指针,是有bug还是不支持这么用呢?因为我看在Excel里透视表是可以跨工作簿直接复制的。
回复 使用道具 举报
Matthew.Xue
超级版主   /  发表于:2025-5-8 12:10:54
7#
Kosen 发表于 2025-5-8 11:43
好的谢谢!不过目前我采用了楼上Lewis的方案,相对实现容易一点。可以帮忙也评估下这个方案有没有啥问题 ...

lewis的方案保存并重新打开了Data表,和我一开始和你说的方案是相同的,由于内存占用问题,就没有使用了。
关于为何直接fromjson会报错,我会和研发确认一下,请耐心等待。
回复 使用道具 举报
Kosen
金牌服务用户   /  发表于:2025-5-8 12:21:06
8#
Matthew.Xue 发表于 2025-5-8 12:10
lewis的方案保存并重新打开了Data表,和我一开始和你说的方案是相同的,由于内存占用问题,就没有使用了 ...

是的,主要之前fromJson整个Workbook还是会保留公式。我试试整个workbook.toJson并加上Serilize options,如果有透视表会不会报错
回复 使用道具 举报
Kosen
金牌服务用户   /  发表于:2025-5-8 14:23:35
9#
Matthew.Xue 发表于 2025-5-8 12:10
lewis的方案保存并重新打开了Data表,和我一开始和你说的方案是相同的,由于内存占用问题,就没有使用了 ...

我目前尝试了workbook的fromSjsJson()和fromJson(),看起来都是可以的,这两种方案的话是不是sjs会效率更高一点呀?
  1. String fileName = "790f6f4ad0d74100b1c85aae4ebc415c_tmp";
  2.         String filePath = "D:\\MyDownloads\" + fileName + ".sjs";
  3.         Workbook workbook = new Workbook();
  4.         workbook.open(filePath, OpenFileFormat.Sjs);
  5.         // 把报表页固化复制到一个临时工作簿中
  6.         Workbook tmpWorkbook = new Workbook();
  7.         // 方案1: sjsJson
  8.         SjsSaveOptions saveOptions = new SjsSaveOptions();
  9.         saveOptions.setIncludeFormulas(false);
  10.         tmpWorkbook.fromSjsJson(workbook.toSjsJson(saveOptions));
  11.         // 方案2: json
  12. //        SerializationOptions options = new SerializationOptions();
  13. //        options.setIgnoreFormula(true);
  14. //        tmpWorkbook.fromJson(workbook.toJson(options));
  15.         tmpWorkbook.getWorksheets().get("Data").delete();
  16.         tmpWorkbook.save( "D:\\MyDownloads\" + fileName + "_tmp.xlsx");
复制代码
回复 使用道具 举报
Matthew.Xue
超级版主   /  发表于:2025-5-8 14:32:43
10#
Kosen 发表于 2025-5-8 14:23
我目前尝试了workbook的fromSjsJson()和fromJson(),看起来都是可以的,这两种方案的话是不是sjs会效率更 ...

sjs的效率会高一些,但是重点应该测试大数据量下,内存占用情况以及耗时你们是否可以接受,几种实现方式目前已经确定了,就看哪种效率更高一些。
回复 使用道具 举报
12下一页
您需要登录后才可以回帖 登录 | 立即注册
返回顶部