我有一个非常大的文件(200GB)。显然,当我将其转移过来时,它没有正确复制。两者的 sha1 哈希值不同。有没有办法可以将文件分成块(如 1MB 或 64MB)并为每个块输出哈希值?然后比较/修复?
我可能只是写一个快速的应用程序来做到这一点。
答案1
这个“快速应用程序”已经存在,并且相对常见:rsync。当然,rsync 的作用远不止于此,但您想要的相当简单:
rsync -cvP --inplace user@source:src-path-to-file dest-path-to-file # from the destination
rsync -cvP --inplace src-path-to-file user@dest:dest-path-to-file # from the source
默认情况下,将使用 ssh(或者可能是 rsh,在非常旧的版本上)来建立连接并传输数据。其他方法也是可能的。
我通过的选项是:
-c
— 根据校验和跳过,而不是文件大小/运行时间。默认情况下,rsync 会优化并跳过大小和运行时间匹配的传输。-c
强制它计算校验和(就 I/O 而言,这是一项昂贵的操作)。请注意,这是基于块的校验和(除非您告诉它仅执行整个文件),并且它只会传输损坏的块。块大小是自动选择的,但可以被覆盖-B
(我怀疑有任何理由这样做)。-v
— 详细,将提供一些详细信息(正在处理哪个文件)-P
— 打开两个部分文件(因此,如果完成一半,它不会放弃工作)和进度条。--inplace
— 更新现有文件,而不是临时文件(随后将替换原始文件)。使您免于拥有 200GB 的临时文件。也意味着部分文件,因此这-P
是部分冗余的。
顺便说一句:我不确定你是如何进行原始传输的,但如果是 sftp/scp,那么有些事情就非常错误了——它们完全防止网络上的任何损坏。你确实应该找出原因。 RAM 有缺陷是一种相对常见的情况。
答案2
如果您想通过网络连接将文件重新传输到另一台机器,使用rsync。
如果您想了解差异在哪里,最简单的方法是将两个版本放在同一台计算机上。如果您因为带宽太昂贵而不想这样做,可以通过以下方法检查文件块。
此方法依赖于head -c
将文件位置保留在其停止的位置,并预先计算大小以了解在哪里结束循环。
n=$(($(wc -c <very_large_file) / (64*1024*1024) + 1))
i=0
while [ $i -gt $n ]; do
head -c 64m | sha256sum
i=$((i+1))
done <very_large_file
此方法依赖于head -c
将文件位置保留在其停止的位置,并用于cksum
查找每个块的大小(短块表示文件末尾)。
while true; do
output=$(head -c 64m | cksum)
size=${output#* }; size=${output%% *}
if [ $size -eq 0 ]; then break; fi
echo "$output"
done <very_large_file
此方法调用dd
跳到每个块所需的起始位置。
n=$(($(wc -c <very_large_file) / (64*1024*1024) + 1))
i=0
while [ $i -gt $n ]; do
dd if=very_large_file ibs=64m skip=$i count=1 | sha256sum
i=$((i+1))
done <very_large_file