Сортировка двоичных файлов по индексу - PullRequest
1 голос
/ 29 октября 2011

У меня есть двоичный файл, который можно рассматривать как объединение другого подфайла:

ВХОДНОЙ ФАЙЛ:

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

Это информация, которую я имею о каждом подфайле:

  • Начальное смещение
  • длина в байтах
  • Конечная последовательность Заказ

Какой, по вашему мнению, самый быстрый способ создания отсортированного выходного файла?

Например, OUTPUT FILE будет содержать SubFile в следующем порядке:

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

Я думал о:

  • Разделить входной файл, извлекая каждый субфайл на диск, затем объединить их в правильном порядке
  • Использование FileSeek для перемещения по файлу и добавление каждого субфайла в поток BinaryWriter.

Также рассмотрим следующую информацию:

  • Входной файл может быть очень большим (200 МБ ~ 1 ГБ)
  • Для тех, кто знает, я говорю о IBM AFP Files.

Оба моих решения просты в реализации, но, на мой взгляд, действительно не работают.

Заранее спасибо

Ответы [ 2 ]

2 голосов
/ 29 октября 2011

Также, если файл большой, количество идентификаторов не так велико.

Вы можете просто получить все свои идентификаторы, sortindex, offset, length в RAM, а затем отсортировать в 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);

Сортировка структур FileItem в оперативной памяти - O (n log n), но также с 100000 элементов это будет быстро и потребует немного памяти.

Копия является самой медленной частью, используйте 256 килобайт .. 2 мегабайта для блочного копирования, чтобы обеспечить быстрое копирование больших кусков файла A в файл B, однако вы можете отрегулировать объем памяти блочного копирования, выполнив некоторые тесты , всегда помня о том, что каждая машина уникальна.

Бесполезно использовать многопоточный подход, он просто замедлит копирование.

Это очевидно, но, если вы, например, скопируете с диска C: на диск D:, это будет быстрее (конечно, не разделы, а два разных последовательных диска ata).

Учтите также, что вам нужно искать, или в чтении, или в письменной форме, в какой-то момент вам нужно будет искать. Также, если вы разделите исходный файл на несколько файлов меньшего размера, вы заставите ОС искать файлы меньшего размера, и это не имеет смысла, это будет грязно и медленнее, и, вероятно, также будет сложнее кодировать. Учтите также, что если файлы фрагментированы, ОС будет искать их самостоятельно, и это не зависит от вас.

1 голос
/ 29 октября 2011

Первым решением, о котором я подумал, было последовательное чтение входного файла и создание объекта Subfile для каждого подфайла. Эти объекты будут помещены в дерево b +, как только они будут созданы. Дерево упорядочит подфайлы по их SortIndex. Хорошая реализация b-дерева будет иметь связанные дочерние узлы, что позволит вам перебирать субфайлы в правильном порядке и записывать их в выходной файл

другим способом может быть использование файлов с произвольным доступом. Вы можете загрузить все SortIndexes и смещения. затем отсортируйте их и запишите выходной файл отсортированным способом. в этом случае все зависит от того, как работают файлы произвольного доступа. в этом случае все зависит от реализации программы чтения файлов с произвольным доступом. если он просто читает файл до указанной позиции, он не будет очень производительным .. честно говоря, я понятия не имею, как они работают ...: (

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...