Предварительно к мультигигабайтному файлу - PullRequest
10 голосов
/ 22 апреля 2010

Какой самый эффективный способ добавить один символ в файл размером в несколько гигабайт (в моем практическом случае - файл объемом 40 ГБ).

Нет ограничений на реализацию, чтобы сделать это. Это означает, что это может быть инструмент, сценарий оболочки, программа на любом языке программирования, ...

Ответы [ 8 ]

8 голосов
/ 22 апреля 2010

Нет действительно простого решения.Не существует системных вызовов для добавления данных, только для добавления или перезаписи.

Но в зависимости от того, что вы делаете с файлом, вы можете избежать хитрости.Если файл используется последовательно, вы можете создать именованный канал и поместить cat onecharfile.txt bigfile > namedpipe, а затем использовать «namedpipe» в качестве файла.То же самое может быть достигнуто с помощью cat onecharfile.txt bigfile | program, если ваша программа принимает ввод stdin.

Для произвольного доступа можно создать файловую систему FUSE, но, вероятно, она слишком сложна для этого.

Если вы хотитечтобы действительно испачкать руки, выясните, как

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

Это имеетхотя возможности для разрушения вашей файловой системы не рекомендуются;хорошо повеселиться.

4 голосов
/ 22 апреля 2010

Пусть файл имеет начальный блок нулевых символов. Когда вы добавляете символ вперед, читайте блок, вставляйте символ справа налево и записывайте блок обратно. Когда блок заполнен, выполните более дорогую полную перезапись, чтобы добавить еще один нулевой блок. Таким образом, вы можете значительно сократить количество раз, когда вам придется полностью переписать.

Добавлено: Хранить файл в двух подфайлах: A (короткий) и B (длинный). Готовьтесь к А, как вам нравится. Когда A становится «достаточно большим», добавьте A к B (переписав) и очистите A.

Другой способ: сохранить файл как каталог небольших файлов ..., A000003, A000002, A000001.
Просто добавьте файл с наибольшим номером. Когда он станет достаточно большим, создайте следующий файл по порядку.
Когда вам нужно прочитать файл, просто прочитайте их все в порядке убывания.

2 голосов
/ 22 апреля 2010

Возможно, вы сможете инвертировать свою реализацию в зависимости от вашей проблемы: добавьте одиночные символы в конец вашего файла. Когда придет время прочитать файл, прочитайте его в reverse .

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

1 голос
/ 01 сентября 2015

Если вы используете linux, вы можете попробовать использовать пользовательскую версию READ (2), загруженную с LD_PRELOAD, и сделать так, чтобы она добавляла ваши данные при первом чтении.

См. https://zlibc.linux.lu/zlibc.html для вдохновения реализации.

0 голосов
/ 22 апреля 2010

Абсолютно самый высокопроизводительный способ, по-видимому, состоит в том, чтобы перейти к уровню секторов и способу хранения файла. Я не уверен, что ОС станет фактором, но целевая платформа может, в любом случае, нам полезно знать, на чем вы работаете.

Я думаю, что это тот случай, когда C является очевидным выбором, такого рода низкоуровневые вещи - это именно то, чем является язык системного программирования для .

Не могли бы вы рассказать нам, что вы в итоге делаете, было бы интересно.

0 голосов
/ 22 апреля 2010

Вот способ командной строки Windows («DOS»):

Поместите свой 1 символ в prepend.txt

copy /b prepend.txt + myHugeFile fileNameOfCombinedFile
0 голосов
/ 22 апреля 2010

Как я понимаю, это обрабатывается на уровне файловой системы, то есть если вы добавляете данные в файл, он фактически перезаписывает файл. По этой же причине теги ID3 в файлах MP3 дополняются нулями, поэтому будущие обновления не перезаписывают весь файл, а просто обновляют эти зарезервированные байты.

Таким образом, какой бы способ вы ни использовали, вы получите примерно одинаковые результаты. Вы можете попробовать выполнить некоторые тесты с пользовательской функцией копирования, которая читает / записывает более крупные фрагменты, чем системная копия по умолчанию, скажем, 2 МБ или 5 МБ, что может повысить производительность. В конечном итоге, узкие места здесь - это ваш дисковый ввод / вывод.

0 голосов
/ 22 апреля 2010

, если вы хотите добавить этот символ к началу всего файла, в одну сторону

$ echo "C" > tmp
$ cat my40gbfile >> tmp
$ mv tmp my40gbfile

или использовать sed

$ sed -i '1i C' my40gbfile

, если вы хотите добавить символ к каждой строкефайл

$ awk '{print "C"$0}' my40gbfile > temp && mv temp my40gbfile
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...