Я полагаю, что объяснение желания написать собственную реализацию может быть любопытным.
Независимо от того, добавляете ли вы сжатие или нет, если вы просто хотите хранить файлы в архиве, аналогично команде tar
,тогда у вас есть несколько возможных подходов.
Один из фундаментальных решений, которые вы должны сделать, заключается в следующем: как разграничить границы упакованных файлов в архиве?Не рекомендуется использовать специальный символ, поскольку упакованные файлы могут содержать любой символ для начала.
Чтобы отслеживать конец файлов, вы можете использовать длину файла в байтах.Например, вы можете для каждого файла:
- Записать в архив завершенную '\ 0' C-строку, в которой указан упакованный файл.
- Записать в архив off64_tкоторый дает длину в байтах упакованного файла.
- Запись в архив фактических байтов (если есть) упакованного файла.
- (Необязательно) Запись в архив контрольной суммыили CRC упакованного файла.
Повторно выполните это для каждого файла, объединяя результаты без промежуточных символов.
Наконец, когда файлов не осталось, напишите пустую C-строку, ноль символа.
Процесс распаковки:
- Считать C-строку, оканчивающуюся на \ 0, с именем этого упакованного файла.
- Еслиимя пустое, подтвердите, что мы прочитали весь архив, затем выйдите.
- Считайте off64_t, который дает длину упакованного файла.
- Считайте столько байтов, сколько длины упакованного файла изархив и запись в только что созданный распакованный файл.
Снова повторяйте эти шаги до тех пор, пока шаг (2) не завершит программу.
Эта схема, в которой имена файлов чередуются с данными файлов, является работоспособной.У него есть некоторые недостатки.Основная проблема заключается в том, что структура данных не предназначена для произвольного доступа.Чтобы получить информацию о файле в «середине» архива, необходима программа для обработки предыдущих файлов.Программа может вызвать lseek_64
, чтобы пропустить чтение данных программы, которые не нужны, но процессор должен прочитать хотя бы каждое имя файла и каждую длину файла.Длина файла необходима, чтобы пропустить данные файла.Имя файла, как я расположил данные, должно быть прочитано, чтобы определить длину файла.
Так что это неэффективно.Даже если имена файлов не нужно было читать, чтобы получить доступ к размеру файла, тот факт, что сведения о файле разбросаны по всему архиву, означает, что для чтения данных индекса требуется доступ к нескольким диапазонам данных на диске.
Лучшим подходом может быть запись «блока» индексных данных в начало файла.Эта структура данных может выглядеть примерно так:
- Размер первого файла в архиве.
- Имя первого файла в архиве.
- позиция в байтах внутри этого архива, где «первый файл» может находиться как непрерывный блок байтов.
- размер второго файла в архиве ...
И данные в индексе могут повторяться до тех пор, пока файл с пустым именем, опять же, не помечает конец индекса.
Наличие такого индекса неплохо, но сопряжено с трудностями: когда пользователь желаетдобавьте файл в архив, возможно, потребуется увеличить размер индекса.Это может изменить расположение упакованных файлов в архиве - программе архива может потребоваться переместить их, чтобы освободить место для большего индекса.
Файловая структура может становиться все более и более сложной, чтобы удовлетворить все эти различные потребности.Например, индекс может быть спроектирован так, чтобы он всегда выделялся из того, что файловая система считает «страницей» (объем, который ОС считывает или записывает с диска как гранулу минимального размера), и если индекс долженрастут, отдельные "индексные страницы" объединены в цепочку данными о положении файла, ведущими от одной индексной страницы к другой.(Как связанный список, но на диске.) Сложность может продолжаться и продолжаться.