当我使用 openxlsx::write.xlsx
写入相同数据时,我能否确保两个 XLSX 文件完全相同?我认为电子表格中会写入一个时间戳,这意味着同样的数据在一秒钟以上的间隔内编写将创建不同的文件。
例如,当快速连续写入时:
library(openxlsx)
write.xlsx(mtcars, "/tmp/t1.xlsx");write.xlsx(mtcars, "/tmp/t2.xlsx")
文件完全相同:
$ md5sum /tmp/t?.xlsx
c9b5f6509e20dd62b158debfbef376fe /tmp/t1.xlsx
c9b5f6509e20dd62b158debfbef376fe /tmp/t2.xlsx
但是如果我在写入之间睡觉:
unlink("/tmp/t1.xlsx") # remove previous
unlink("/tmp/t2.xlsx")
write.xlsx(mtcars, "/tmp/t1.xlsx");Sys.sleep(2);write.xlsx(mtcars, "/tmp/t2.xlsx")
这都不一样:
$ md5sum /tmp/t?.xlsx
460945a610df3bc8a1ccdae9eb86c1fa /tmp/t1.xlsx
a4865be49994092173792c9f7354e435 /tmp/t2.xlsx
我的用例是生成一个XLSX文件的流程,该文件将被放入git存储库中。如果我自动化这个流程,那么即使源数据没有更改,XLSX文件也会每次都发生变化。我想在流程的早期测试数据是否已更改,如果没有更改,则不生成新的XLSX文件,但让git进行“是否已更改?”测试似乎更容易,但XLSX中的隐形元数据会破坏它。叫我懒。
XLSX的元数据能否设置以防止此问题?我猜可能有一个“创建日期”之类的东西。我不在乎这一直是1970-01-01。
预防性策略:不能使用CSV,XLSX有多个工作表,这是我的最终用户想要的。是的,我已经将其写入SQlite数据库,并且在向其写入相同数据时完全相同。
我认为这不能像现在这样使用openxlsx,因为差异是由于创建了元数据XML:https://github.com/ycphs/openxlsx/blob/7742063a4473879490d789c552bb8e6cc9a0d2c7/R/baseXML.R#L77,其中它将当前的
Sys.time()
放入created
字段。似乎有两个差异来源。首先,有Excel元数据写入到MS Excel文档结构内的
<dcterms:created>
元数据中。但即使将其设置为相同(通过monkey-patching openxlsx
),仍然会留下差异,因为文档使用标准ZIP格式捆绑,并且那里也有日期头。这是两个XLSX文件,未压缩,显示了所有相同的CRC-32值,因此其中的文件是相同的:
Archive: test1.xlsx
Length Method Size Cmpr Date Time CRC-32 Name
-------- ------ ------- ---- ---------- ----- -------- ----
587 Defl:N 234 60% 2022-01-31 15:22 b5dbec60 _rels/.rels
1402 Defl:N 362 74% 2022-01-31 15:22 63422601 [Content_Types].xml
284 Defl:N 173 39% 2022-01-31 15:22 f9153db0 docProps/app.xml
552 Defl:N 278 50% 2022-01-31 15:22 37126cbe docProps/core.xml
696 Defl:N 229 67% 2022-01-31 15:22 14a147d3 xl/_rels/workbook.xml.rels
4500 Defl:N 311 93% 2022-01-31 15:22 285db1ad xl/printerSettings/printerSettings1.bin
601 Defl:N 203 66% 2022-01-31 15:22 211e1d6e xl/sharedStrings.xml
1127 Defl:N 464 59% 2022-01-31 15:22 0d8ee71d xl/styles.xml
7075 Defl:N 1361 81% 2022-01-31 15:22 050f988c xl/theme/theme1.xml
950 Defl:N 382 60% 2022-01-31 15:22 1b8cce29 xl/workbook.xml
612 Defl:N 223 64% 2022-01-31 15:22 f0584777 xl/worksheets/_rels/sheet1.xml.rels
12729 Defl:N 2204 83% 2022-01-31 15:22 18057777 xl/worksheets/sheet1.xml
-------- ------- --- -------
31115 6424 79% 12 files
$ unzip -v test2.xlsx
Archive: test2.xlsx
Length Method Size Cmpr Date Time CRC-32 Name
-------- ------ ------- ---- ---------- ----- -------- ----
587 Defl:N 234 60% 2022-01-31 15:22 b5dbec60 _rels/.rels
1402 Defl:N 362 74% 2022-01-31 15:22 63422601 [Content_Types].xml
284 Defl:N 173 39% 2022-01-31 15:22 f9153db0 docProps/app.xml
552 Defl:N 278 50% 2022-01-31 15:22 37126cbe docProps/core.xml
696 Defl:N 229 67% 2022-01-31 15:22 14a147d3 xl/_rels/workbook.xml.rels
4500 Defl:N 311 93% 2022-01-31 15:22 285db1ad xl/printerSettings/printerSettings1.bin
601 Defl:N 203 66% 2022-01-31 15:22 211e1d6e xl/sharedStrings.xml
1127 Defl:N 464 59% 2022-01-31 15:22 0d8ee71d xl/styles.xml
7075 Defl:N 1361 81% 2022-01-31 15:22 050f988c xl/theme/theme1.xml
950 Defl:N 382 60% 2022-01-31 15:22 1b8cce29 xl/workbook.xml
612 Defl:N 223 64% 2022-01-31 15:22 f0584777 xl/worksheets/_rels/sheet1.xml.rels
12729 Defl:N 2204 83% 2022-01-31 15:22 18057777 xl/worksheets/sheet1.xml
但是文件仍然不同:
$ md5sum test1.xlsx test2.xlsx
27783e8b19631039a1c940db214f25e1 test1.xlsx
ba0678946aea1e01093ce25130b2c467 test2.xlsx
由于 ZIP 元数据,可以使用
exiftool
查看:$ exiftool test*.xlsx | grep Zip | grep Date
Zip Modify Date : 2022:01:31 15:22:52
Zip Modify Date : 2022:01:31 15:22:54
Excel
中打开这两个版本,并将它们保存为xml
,你会发现唯一的区别在于字段<Created>2022-01-31T14:24:33Z</Created>
。 - Waldiopenxlsx
设置它的位置。除了分叉该软件包之外,我看不出有什么简单的方法可以解决这个问题。也许可以考虑使用其他软件包... - Spacedmansystem(sudo date --set[...])
这样的方式。缺点可能在于设置日期和xls之间存在不同的延迟时间... - Grzegorz Sapijaszko