(写在前面:这个问题似乎还没有研究完)
就在本周,同事跟我说了个非常神奇的现象,之前做的表格在公司的电脑上打开没有任何问题,但是到了自己的笔记本上打开反而非常卡,卡到连工作表都切不动,随便动一下就程序未响应,于是找我说了下这个事情。
我要他把有问题的文档发给我我看下,同时我们确认了两台电脑环境差异和文件异常的地方:
1、公司的电脑是Excel2007,同事自己的笔记本是Excel2019
2、文件体积相比同类型文件大了至少三倍
3、Excel2007打开以后操作非常流畅,但是到了Excel2019就非常卡顿
4、笔记本上甚至连点这个文件右键菜单都要转一下才出来
5、公司的PC配置非常老,运行效率低下,同事的笔记本是新买的,4800H+固态,打开其他文件非常迅速
因为是xlsx文档,所以就直接改成zip看文档内容到底有什么了:
乍一看好像没啥不对,但是点开drawings之后就发现问题了。。
drawings文件夹记录的是Excel文档的绘图形状,然而据同事说表里根本不可能有绘图形状之类的东西,所以暂且认为drawings文件夹是多余的,但是为了保险起见还是强行点开了文件看里面是不是有大量不可见的绘图形状
结果,还真有。。。在非常不起眼的角落发现了难以察觉的绘图形状
那么接下来就是想办法删掉这部分绘图形状了,三个办法:
一是换2007(你这不等于没说吗!)
二是直接在压缩包里删掉drawings文件夹,由于删掉drawings文件夹后会导致文件缺失,Excel在打开的时候会修复文档,同时删除不存在的绘图形状组件
如果能正常修复完,文件再另存为其实就已经和之前的文件没什么两样了。
但是这种粗暴的方法对于2010以后版本的Excel又是灾难性的,因为Excel2010以后的版本在很多电脑上很可能都没开始修复就崩溃了,所以如果这种方法导致了电脑崩溃,请往后看。
三是通过vba解决,在工作簿标签上点右键打开查看代码输入下面的代码就可以删掉所有绘图形状了(虽然可以用,但是有副作用,因为是删除对象,而对象又不止绘图形状,图表好像也属于对象,同时如果确实有要用的绘图形状既不能用方法一也不能用方法二而是只能老老实实换Excel2007挨个看)
Sub a()
Dim draw As Object
For i = 1 To Sheets.Count
Sheets(i).Select
On Error Resume Next
For Each draw In ActiveSheet.Shapes
draw.Delete
Next draw
Next
End Sub
当删除掉所有对象后,一般的表格这个时候就应该恢复正常了,不管怎样操作都和之前在Excel2007一样
当然以上三种办法无论哪一种,都是直接删除掉所有对象,如果有要保留的对象,就要考虑选择性删除了。
关于被忽略掉的部分:
实际上,还没完。
在之前的文档里,我们发现除了绘图形状以外,还有一个文件夹——ctrlProps
后来发现,这个文件夹的文件居然高达49000+个,即便压缩过后也为文件增加了不小的体积
目前猜测是这部分文件应该是兼容性检查后留下的信息,每当一个单元格的公式或者格式会有兼容性问题,就会被记录一个文件保存在ctrProps,然而诡异的是只有xlsx保存为xls才会有兼容性问题,xls保存为xlsx后由于不存在兼容性问题,兼容性检查的信息会被清空掉,为什么在这个xlsx文件里依然有这部分信息呢?难以理解。
要清理掉这部分文件也很简单,由于前面的步骤已经清理了drawings下的文件了,绘图形状已经没有了,因此只要重新将文件另存为xls,再另存为xlsx就可以了
关于实际文件读写层面的处理:(12月1日更新)
实际上上述情况产生文件体积过大和卡顿的根本原因只有两个——多余的兼容性检查信息和多余的绘图形状
在前面我说过,方法二是直接删除drawings文件夹,有人可能会问,为什么ctrlProps不能这样?
这点我无法解答,实际上从Excel修复来看,两种组件的修复逻辑是不一样的,drawings在修复的时候看的是文档里有没有记录drawing的相关信息,如果没有,就在[Content_Types].xml里直接删掉组件与主文档的关联
而ctrlProps就不一样,就算删掉了文件夹,由于[Content_Types].xml有该部分组件与主文档的关联,Excel会试着尝试重新检查兼容性,但是由于Excel尝试修复的次数是有上限的,因此修复完成的文档你会发现这部分兼容性信息又回来了,而更多的情况可能是因为超过修复次数上限导致修复失败认为文件已损坏
是的,完全不一样
drawings其实跟[Content_Types].xml一点关系也没有
drawings在文件里确实是保存在xl路径下的,但是与文档的关联并不在[Content_Types].xml,而是在xl\worksheets\下每一个sheet*.xml文件里
(sheet*.xml里部分drawing信息)
这也就是为什么直接删掉drawings文件夹后,Excel在修复时会直接删掉所有绘图形状。因为对应的信息没有了,Excel认为这部分数据完全丢失无法复原了,因此直接删掉了绘图形状
这个修复逻辑像极了批注的修复逻辑
然而ctrlProps不一样
文档的兼容性信息是写进[Content_Types].xml里的,如果丢失了会强制修复,因此这部分信息暴力删除不可取,只能以另存为的方法得到干净的[Content_Types].xml后替换原有的[Content_Types].xml,再删除ctrlProps才能顺利删掉这部分多余的信息