将字符串的 MD5 和与文件内容进行比较

Comparing the MD5 sum of a string to the contents of a file

我正在尝试将一个字符串(在内存中)与一个文件的内容进行比较,看它们是否相同。如果有人关心的话,关于动机的无聊细节在问题下面。

我的困惑是,当我对文件内容进行哈希处理时,得到的结果与对字符串进行哈希处理时得到的结果不同。

library(readr)
library(digest)

# write the string to the file
the_string <- "here is some stuff"
the_file <- "fake.txt"
readr::write_lines(the_string, the_file)

# both of these functions (predictably) give the same hash
tools::md5sum(the_file)
# "44b0350ee9f822d10f2f9ca7dbe54398" 

digest(file = the_file)
# "44b0350ee9f822d10f2f9ca7dbe54398"

# now read it back to a string and get something different
back_to_a_string <- readr::read_file(the_file)
# "here is some stuff\n"

digest(back_to_a_string)
# "03ed1c8a2b997277100399bef6f88939"

# add a newline because that's what write_lines did
orig_with_newline <- paste0(the_string, "\n")
# "here is some stuff\n"

digest(orig_with_newline)
# "03ed1c8a2b997277100399bef6f88939"

想要做的只是digest(orig_with_newline) == digest(file = the_file)看看它们是否相同(它们是)但是returns FALSE 因为,如图所示,哈希不同。

显然,我可以使用 read_file 将文件读回字符串或将字符串写入临时文件,但这两种方法看起来都有些愚蠢和老套。我想这两个实际上都是很好的解决方案,我真的只是想了解为什么会发生这种情况,以便我可以更好地理解散列的工作原理。

无聊的动机细节

情况是我有一个函数可以将字符串写入文件,但如果文件已经存在,那么它将出错,除非用户已明确传递 .overwrite = TRUE。但是,如果文件存在,我想检查要写入文件的字符串是否实际上与文件中已有的字符串相同。如果是这种情况,那么我将跳过错误(和写入)。可以在循环中调用此代码,如果用户不断看到此错误,即他们将要用其中已有的相同内容覆盖文件,这将是令人讨厌的。

简短回答:我认为您需要设置 serialize=FALSE。假设文件不包含额外的换行符(见下文),

digest(the_string,serialize=FALSE) ==  digest(file=the_file) ## TRUE

serialize 对命令的 file= 版本没有影响)

处理换行符

如果你阅读?write_lines,它只会说

sep: The line separator ... [information about defaults for different OSes]

对我来说,关于是否在最后一行之后添加分隔符似乎是模棱两可的。 (您不希望“逗号分隔列表”以逗号结尾 end ...)

另一方面,?base::writeLines更明确一点,

sep: character string. A string to be written to the connection after each line of text.

如果深入研究 source code of readr,您会发现它使用

      output << na << sep;

对于每一行代码,即它的行为方式与 writeLines.

相同

如果你真的只想将字符串写入文件而不添加任何废话,我建议cat():

identical(the_string, { cat(the_string,file=the_file); readr::read_file(the_file) }) ## TRUE