使用 data.table 和 R.utils 获取压缩文件的一致 md5 校验和

Get consistent md5 checksum of gzipped file using data.table and R.utils

我正在尝试使用 R.utils::gzipdata.table::fwritecompress = "gzip" 参数复制压缩文件的校验和,但我总是得到不同的结果。这是一个例子

library(data.table); library(R.utils); library(digest)

dt <- data.frame(a = c(1, 2, 3))

fwrite(dt, "r-utils.csv")
gzip("r-utils.csv")
fwrite(dt, "datatable-v1.csv.gz", compress = "gzip")

digest(file = "r-utils.csv.gz")
#> [1] "8d4073f4966f94ac5689c6e85de2d92d"
digest(file = "datatable-v1.csv.gz")
#> [1] "5d58f9eeefb166c6d50ac00f3215e689"

最初我虽然 fwrite 将文件名和时间戳存储在输出文件中(根据没有 --no-name 选项的通常 gzip 行为),但没有出现之所以如此,是因为我在对 fwrite

的不同调用中得到了相同的校验和
fwrite(dt, "datatable-v2.csv.gz", compress = "gzip")
digest(file = "datatable-v2.csv.gz")
#> [1] "5d58f9eeefb166c6d50ac00f3215e689"

关于可能导致差异的原因有什么想法吗?

PS。顺便提一下,解压文件的校验和是一样的

$ md5sum datatable-v1.csv 
7e034138dc91aa575d929c1ed65aa67c  datatable-v1.csv
$ md5sum r-utils.csv 
7e034138dc91aa575d929c1ed65aa67c  r-utils.csv

如果你查看字节,你会发现它们是不同的

r-utils.csv.gz
  Offset: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F   
00000000: 1F 8B 08 00 00 00 00 00 00 06 4B E4 E5 32 E4 E5    ..........Kde2de
00000010: 32 E2 E5 32 E6 E5 02 00 21 EB 62 BF 0C 00 00 00    2be2fe..!kb?....

datatable-v2.csv.gz
  Offset: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F   
00000000: 1F 8B 08 00 00 00 00 00 00 0A 4B E4 E5 02 00 56    ..........Kde..V
00000010: EF 2F E3 03 00 00 00 1F 8B 08 00 00 00 00 00 00    o/c.............
00000020: 0A 33 E4 E5 32 E2 E5 32 E6 E5 02 00 49 C4 FF 4D    .3de2be2fe..ID.M
00000030: 09 00 00 00                                        ....

所以 data.table 一个更长。这似乎是因为默认压缩设置不同。具体来说,这两种方法似乎使用了不同的“window size”参数。 data.table code uses a windowBits value of 31 (15+16) which will include "trailing checksum in the output" but the R.utils::gzip function uses the base R gzfile() function which uses a windowBits value of -15 (MAX_WBITS) 和那个负值意味着不应使用尾随校验和。所以我认为这解释了 data.table 输出中的额外字节。

因为您可以使用不同的压缩级别设置和校验和以及 gzip headers,所以如果使用两个不同的压缩管道,您不一定会为数据文件的压缩版本获得相同的校验和。所以有可能里面的数据是一样的,但实际的压缩文件是不同的。

由于这些设置是包的 C 代码的一部分,并且对于基础 R,这不是您可以在 R 代码中更改的内容。这两种不同的方法不可能 return 相同的输出。