基于二进制文件索引的排序

时间:2011-10-29 15:53:35

标签: c# java .net afp

我有一个二进制文件,可以看作是不同子文件的串联:

输入文件:

Hex Offset     ID           SortIndex
0000000        SubFile#1    3
0000AAA        SubFile#2    1
0000BBB        SubFile#3    2
...
FFFFFFF        SubFile#N    N

这些是我对每个SubFile的信息:

  • 开始偏移
  • 长度以字节为单位
  • 最终序列顺序

您认为生成分类输出文件的最快方法是什么?

例如,OUTPUT FILE将按以下顺序包含SubFile:

SubFile#2    
SubFile#3    
SubFile#1    
...

我想过:

  • 拆分输入文件,将每个子文件解压缩到磁盘,然后 按正确的顺序连接它们
  • 使用FileSeek移动文件并将每个SubFile添加到BinaryWriter Stream。

还要考虑以下信息:

  • 输入文件可能非常庞大(200MB~1GB)
  • 对于那些知道的人,我说的是IBM AFP文件。

我的解决方案都很容易实现,但在我看来看起来真的没有。

提前致谢

2 个答案:

答案 0 :(得分:2)

如果文件很大,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个项目,它将会很快并且将使用少量内存。

副本是最慢的部分,使用256千字节... 2兆字节进行块复制,以确保将大块文件A复制到文件B会很快,但是你可以调整块复制内存的数量来做一些测试,始终牢记每台机器都不同。

尝试多线程方法没有用,它只会减慢副本速度。

很明显,但是,如果你从驱动器C:复制到驱动器D:,它会更快(当然,不是分区,而是两个不同的串行ata驱动器)。

考虑到你需要寻求,或者在阅读或书面形式,你需要寻求。此外,如果您将原始文件拆分为几个较小的文件,您将使操作系统搜索较小的文件,这没有意义,它将是混乱和较慢的,并且可能也更难编码。 还要考虑如果文件碎片化,操作系统将自行查找,这是你无法控制的。

答案 1 :(得分:1)

我想到的第一个解决方案是按顺序读取输入文件并为每个子文件构建一个Subfile对象。这些对象一旦创建就会被放入b + tree中。树将按其SortIndex对子文件进行排序。一个好的b-tree实现将链接子节点,这使您能够以正确的顺序迭代子文件并将它们写入输出文件

另一种方法可能是使用随机访问文件。您可以加载所有SortIndexes和偏移量。然后对它们进行排序并以排序的方式写入输出文件。在这种情况下,所有取决于随机访问文件的工作方式。在这种情况下,所有都取决于随机访问文件阅读器实现。如果它只是读取文件直到指定的位置它不会是非常高效的...老实说,我不知道它们是如何工作的...... :(