将小文件拆分为 512 字节段会改变它,但将其拆分为 1k 段不会改变它

Fla*_*erX 16 find dd wildcards split checksum

所以我试图将 64MB 文件分割FileCarve.001成 512 字节段(每个块长 512 字节)。我需要确保文件在分割成较小的文件时具有相同的数据,因此我将cat所有文件进行标准输出并将其通过管道传输到sha256sum(有很多文件,所以我需要使用find和 来执行此操作xargs)。

当命令分割输出时,将文件分割为 512 字节段似乎会导致数据混乱split

$ dd if=FileCarve.001 bs=512 | split -b512 - splits/img
131072+0 records in
131072+0 records out
67108864 bytes (67 MB, 64 MiB) copied, 4.10824 s, 16.3 MB/s
$ sha256sum FileCarve.001 
3e64100044099b10060f5ca3194d4d60414941c7cb26437330aba532852a60cd  FileCarve.001
$ find splits/ -type f -print0 | xargs -0 cat | sha256sum
25b37f28204895e5d0b1cb160c5fa599d15188baf7e529ccc92a10fdb3f0515a  -
Run Code Online (Sandbox Code Playgroud)

但将文件分割为 1 KB 段(1000 字节)似乎效果很好。

$ dd if=FileCarve.001 bs=512 | split -b1k - splits/img
131072+0 records in
131072+0 records out
67108864 bytes (67 MB, 64 MiB) copied, 2.06029 s, 32.6 MB/s
$ sha256sum FileCarve.001 
3e64100044099b10060f5ca3194d4d60414941c7cb26437330aba532852a60cd  FileCarve.001
$ find splits/ -type f -print0 | xargs -0 cat | sha256sum
3e64100044099b10060f5ca3194d4d60414941c7cb26437330aba532852a60cd  -
Run Code Online (Sandbox Code Playgroud)

为什么它们不同?关于块在存储设备上的工作方式,有什么我不明白的地方吗?

回应评论:我确实split/在每次运行时清除了目录。

ilk*_*chu 40

find处理文件的顺序是不确定的。它可能与底层系统调用给出的顺序相同,这可能取决于底层文件系统结构并且本质上可以是随机的。某些实现可能会以某种方式处理列表,但不要期望它会被排序。

让我们尝试使用较小的文件。cat frag*重现正确的文件,因为 shell glob 确实对文件名进行排序:

$ split -b512 orig.bin frag
$ cat frag* > new.bin
$ sha256sum orig.bin new.bin 
8d12b42623eeefee872f123bd0dc85d535b00df4d42e865f993c40f7bfc92b1e  orig.bin
8d12b42623eeefee872f123bd0dc85d535b00df4d42e865f993c40f7bfc92b1e  new.bin
Run Code Online (Sandbox Code Playgroud)

find事实并非如此,所以我们得到了一个不同的文件:

$ find . -name 'frag*' -exec cat {} + > second.bin
$ sha256sum second.bin 
821325739ca65d1cb568ecf3a16bd2e01ac4eef1419b4d714834fab07d2f135c  second.bin
Run Code Online (Sandbox Code Playgroud)

只需运行find打印名称就可以很好地揭示这一点:

$ find . -name 'frag*' |head -5
./fragzbgv
./fragzbmg
./fragvt
./fragyd
./fragzayc
Run Code Online (Sandbox Code Playgroud)

那是在 Linux 和 ext4 上。我认为它使用某种哈希和树来存储文件名,从而产生看起来随机的顺序。在 tmpfs 上,我以相反的创建顺序获得了列表,这不是随机的,但仍然会弄乱这种情况。

对文件名列表进行显式排序应该会有所帮助:

$ find . -name 'frag*' -print0 | sort -z | xargs -0 cat > third.bin
$ sha256sum third.bin 
8d12b42623eeefee872f123bd0dc85d535b00df4d42e865f993c40f7bfc92b1e  third.bin
Run Code Online (Sandbox Code Playgroud)

事实上,它对 1k 块有效,可能是一个意外......


顺便说一句,我不确定您为什么要使用dd bs=512那里的输入而不是直接cat给出split文件名。所做的事情是使用特定的块大小进行读取和写入,但是和dd之间的管道不保存块大小,它只是字节流,并且文件系统实际上不应该关心您使用什么块大小来读取文件,是它是 512 (2^8) 或 521(质数)字节。ddsort

  • @FlashDaggerX,嗯,这是 SE 问题的一部分。如果您认为未来的读者可以更轻松地找到其他措辞,并且愿意进行编辑,那么请继续。但它描述了您所看到的行为,这也没关系。 (8认同)
  • 关于*它的顺序与底层系统调用给出的顺序相同*。这不一定是真的。众所周知,有些会按 inode 对文件列表进行排序,例如作为一种优化(以最大限度地减少 HDD 磁头搜索次数或利用 inode 表的预取和缓存)。(无论如何,它仍然会显示为随机) (4认同)