Быстрая конкатенация нескольких файлов в Linux - PullRequest
12 голосов
/ 05 мая 2011

Я использую многопроцессорную обработку Python для создания временного выходного файла для каждого процесса. Их размер может быть несколько ГБ, и я делаю несколько десятков таких. Эти временные файлы должны быть объединены для формирования желаемого результата, и этот шаг оказывается узким местом (и убийцей параллелизма). Существует ли инструмент Linux, который будет создавать объединенный файл, изменяя метаданные файловой системы, а не копировать содержимое? Пока это работает на любой системе Linux, которая была бы приемлема для меня. Но конкретное решение для файловой системы не очень поможет.

Я не обучен ОС или CS, но теоретически представляется возможным создать новый инод и скопировать структуру указателя инода из инода файлов, из которых я хочу копировать, и затем отсоединить эти иноды. Есть ли какая-нибудь утилита, которая сделает это? Учитывая избыток хорошо продуманных утилит unix, я полностью ожидал, что это произойдет, но ничего не смог найти. Отсюда мой вопрос по ТАК. Файловая система находится на блочном устройстве, фактически на жестком диске, если эта информация имеет значение. У меня нет уверенности, что я смогу написать это самостоятельно, поскольку я никогда раньше не занимался программированием на системном уровне, поэтому любые указатели (на фрагменты кода C / Python) будут очень полезны.

Ответы [ 6 ]

14 голосов
/ 05 мая 2011

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

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

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

  2. Запустите многопроцессорную обработку, передав каждый процесс FD и смещению в его определенный фрагмент файла.

Таким образом, процессы будут совместно заполнять один выходной файл, избавляя от необходимости катать их вместе позже.

EDIT

Если вы не можете предсказать размер отдельных файлов, но потребитель Конечный файл может работать с последовательным (в отличие от произвольного доступа) вводом, вы можете подача cat tmpfile1 .. tmpfileN потребителю, либо на стандартный

cat tmpfile1 ... tmpfileN | consumer

или по именованным каналам (с использованием подстановки процессов в bash):

consumer <(cat tmpfile1 ... tmpfileN)
5 голосов
/ 05 мая 2011

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

В этом решении ваши производящие и потребляющие приложения остаются без изменений. Производители записывают кучу файлов, которые слой FUSE заставляет отображаться как один файл. Этот виртуальный файл затем представляется потребителю.

FUSE имеет привязки для нескольких языков, включая Python . Если вы посмотрите на некоторые примеры здесь или здесь (это для разных привязок), это требует удивительно небольшого кода.

2 голосов
/ 18 сентября 2013

для 4 файлов;xaa, xab, xac, xad быстрая конкатенация в bash (от имени root):

losetup -v -f xaa; losetup -v -f xab; losetup -v -f xac; losetup -v -f xad

(Предположим, что loop0, loop1, loop2, loop3 являются именами файлов новых устройств.)

Поместите http://pastebin.com/PtEDQH7G в файл сценария join_us.Затем вы можете использовать его следующим образом:

./join_us /dev/loop{0..3}

Затем (если этот большой файл - фильм) вы можете передать его право собственности обычному пользователю (chown itsme / dev / mapper / join), а затем он /она может воспроизвести его через: mplayer / dev / mapper / join

Очистка после них (от имени root):

dmsetup remove joined; losetup -d /dev/loop[0123]
2 голосов
/ 05 мая 2011

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

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

РЕДАКТИРОВАТЬ

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

$ mkfifo /tmp/cat
$ cat file1 file2 ... >/tmp/cat &
$ user_program /tmp/cat
...
$ rm /tmp/cat
0 голосов
/ 05 мая 2011

Потенциальная альтернатива - поместить все ваши временные файлы в именованный канал, а затем использовать этот именованный канал в качестве входных данных для вашей программы с одним входом. Пока ваша программа с одним входом просто читает входные данные последовательно и не ищет.

0 голосов
/ 05 мая 2011

Нет, такого инструмента или системного вызова нет.

Вы могли бы исследовать, возможно ли для каждого процесса записать непосредственно в окончательный файл.Скажем, процесс 1 записывает байты 0-X, процесс 2 пишет X-2X и т. Д.

...