基于二进制文件索引排序
本文关键字:排序 索引 二进制文件 | 更新日期: 2023-09-27 18:12:49
我有一个二进制文件,可以看作是不同子文件的连接:
输入文件:Hex Offset ID SortIndex
0000000 SubFile#1 3
0000AAA SubFile#2 1
0000BBB SubFile#3 2
...
FFFFFFF SubFile#N N
这些是我对每个子文件的信息:
- 字节长度
- 最终序列命令
在你看来,什么是最快的方式来产生一个排序输出文件?
例如,OUTPUT FILE将按以下顺序包含子文件:
SubFile#2
SubFile#3
SubFile#1
...
我想过:
- 分割输入文件提取每个子文件到磁盘,然后按正确的顺序将它们连接起来
- 使用FileSeek来移动文件并将每个子文件添加到BinaryWriter流。
还要考虑以下信息:
- 输入文件可能非常大(200MB~1GB)
- 对于那些知道的人,我说的是IBM AFP文件。
我的两个解决方案都很容易实现,但在我看来,看起来真的不执行。
Thanks in advance
如果文件很大,id的数量也不会那么大。
你可以在RAM中获取所有id,sortindex,偏移量,长度,然后在RAM中使用简单的快速排序进行排序,当你完成后,你可以按照排序数组中的顺序重写整个文件。我希望这种方法比其他方法更快。所以…让我们编写一些伪代码。
public struct FileItem : IComparable<FileItem>
{
public String Id;
public int SortIndex;
public uint Offset;
public uint Length;
public int CompareTo(FileItem other) { return this.SortIndex.CompareTo(other.SortIndex); }
}
public static FileItem[] LoadAndSortFileItems(FILE inputFile)
{
FileItem[] result = // fill the array
Array.Sort(result);
}
public static void WriteFileItems(FileItem[] items, FILE inputfile, FILE outputFile)
{
foreach (FileItem item in items)
{
Copy from inputFile[item.Offset .. item.Length] to outputFile.
}
}
读操作的次数是线性的,O(n),但是需要查找。搜索的唯一性能问题是硬盘缓存丢失。现代硬盘有一个很大的缓存,从8到32兆字节,查找一个随机顺序的大文件意味着缓存丢失,但我不会担心太多,因为花在复制文件上的时间,我猜,比查找所需的时间要多。
如果使用固态磁盘,则查找时间为0:)
然而,编写输出文件是O(n)和顺序的,这是一件非常好的事情,因为您将完全缓存友好。如果您在开始写入文件之前预先分配文件的大小,您可以确保更好的时间。 FileStream myFileStream = ...
myFileStream.SetLength(predictedTotalSizeOfFile);
在RAM中排序FileItem结构是O(n log n),但是对于100000个项目,它将很快并且将使用少量内存。
拷贝是最慢的部分,使用256kb ..2兆字节用于块复制,以确保将文件A的大块复制到文件B的速度很快,但是您可以通过一些测试来调整块复制内存的数量,始终记住每台机器都是不同的。
尝试多线程方法是没有用的,它只会减慢复制速度。
这很明显,但是,如果您从驱动器C:复制到驱动器D:,它会更快(当然,不是分区,而是两个不同的串行数据驱动器)。
还考虑到你需要seek,或者在阅读或写作中,在某些时候,你需要seek。另外,如果您将原始文件分割成几个较小的文件,您将使操作系统寻找较小的文件,这是没有意义的,它将是混乱的,速度较慢,并且可能也更难编写代码。还要考虑到,如果文件碎片化,操作系统将自行查找,这是您无法控制的。
我想到的第一个解决方案是依次读取输入文件,并为每个子文件构建一个subfile -object。这些对象一旦被创建,就会被放入b+树中。树将根据子文件的SortIndex排序。一个好的b-tree实现将具有链接的子节点,使您能够以正确的顺序遍历子文件并将它们写入输出文件
另一种方法是使用随机访问文件。你可以加载所有的SortIndexes和偏移量。然后对它们进行排序,并以排序的方式写入输出文件。在这种情况下,一切都取决于随机访问文件的工作方式。在这种情况下,一切都取决于随机访问文件读取器的实现。如果它只是读取文件,直到指定的位置,它将不是很性能。老实说,我不知道它们是怎么工作的……(