是否有用于对包含固定长度二进制记录的大文件进行排序的 Unix 实用程序?
换句话说,我正在寻找类似 sort(1) 但具有固定长度记录的二进制文件。
我可以将文件转换为文本,然后使用 sort(1) 进行排序,然后转换回二进制表示,但我正在寻找更节省时间和空间的方法。
答案1
事实证明你很幸运;有一个 GNU 风格的 unix 程序可以做到这一点:排序。
bsort
是一种超高效的就地基数排序实现,在处理大于 RAM 的文件时会仔细注意内存访问模式。我说的高效是指能够超越http://sortbenchmark.org2014 年年中,在硬件上实现了 10^8 的节能排序记录 - 记录为 889 焦耳,其早期原型能够在普通的 MacBook Pro 上以 335 焦耳完成相同的排序。对于完全装入 RAM(三位数兆字节)的“小型”数据集,它比 libc 的 qsort 库快 3 倍左右。
答案2
一种解决方案是将输入文件转换为十六进制,将每个记录编码在单独的行上,对其进行排序,然后转换回二进制:
record_size=32
cat input \
|xxd -cols $record_size -plain \
|sort \
|xxd -cols $record_size -plain -revert
但是速度很慢(xxd 在我的计算机上大约为 40MB/s)
因此,由于我需要它,所以我写了binsort
,其作用是:
binsort --size 32 ./input ./output
使用--size 32
,它假设 32 字节固定大小的记录,读取./input
,将排序后的记录写入./output
。
答案3
如果您引用相对于第一个“记录”的二进制数据,则 Unix 的排序实用程序可以根据记录内的字节位置对二进制数据进行排序。例如 -k1.28,1.32。
Unix 排序在行尾概念方面不太灵活。根据您的数据,您可能能够执行比 user68497 建议的基于 xxd 的更简单的流编辑,并使用以空结尾的行。不过,这仍然可能涉及大量内存数据复制,并且不会接近基于 mmap 的方法的速度。
但是如果您以某种方式使用 unix 排序,请注意语言环境。排序假定其输入是文本,而语言环境会影响排序顺序。