Самый быстрый способ объединения файлов

25

У меня есть 10k + файлов общим объемом более 20 ГБ, которые мне нужно объединить в один файл.

Есть ли более быстрый способ, чем

cat input_file* >> out

?

Предпочтительным способом была бы команда bash, Python также приемлем, если не значительно медленнее.

fsperrle
источник
Обновил мой ответ, findне сортирует файлы так же, как глобус оболочки.
Грэм
5
Любые и все (нормальные) решения будут иметь эквивалентную скорость, так как время ввода-вывода будет 99%.
Златовласка
3
Рассматривая запись объединенного файла на диск, отличный от того, с которого вы читаете.
Луис
1
Это будет быстрее, если outнаходится на другом диске.

Ответы:

30

Нет, кошка, безусловно, лучший способ сделать это. Зачем использовать python, если для этого уже написана программа на C? Тем не менее, вы можете рассмотреть возможность использования xargsв случае, если длина командной строки превышает ARG_MAXи вам нужно более одного cat. Используя инструменты GNU, это эквивалентно тому, что у вас уже есть:

find . -maxdepth 1 -type f -name 'input_file*' -print0 |
  sort -z |
  xargs -0 cat -- >>out
Graeme
источник
1
Можете ли вы в этом случае убедиться, что ваши файлы будут прочитаны в порядке?
Kiwy
1
Да, потому что вывод по findканалу sort. Без этого файлы будут перечислены в произвольном порядке (определенном файловой системой, что может быть порядком создания файла).
Scai
@scai Я скучаю извините, с сортировкой это довольно очевидно
Kiwy
1
@Kiwy, единственный случай, который я вижу, это если языковой стандарт не установлен должным образом в среде, тогда сортировка может вести себя иначе, чем bashглобальные. В противном случае я не вижу случаев, когда xargsили catне будет вести себя, как ожидалось.
Грэм
3
@MarcvanLeeuwen, xargsбудет вызывать по catмере необходимости, чтобы избежать ошибки E2BIG в execve (2).
Стефан Шазелас
21

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

Например, если в Linux:

size=$({ find . -maxdepth 1 -type f -name 'input_file*' -printf '%s+'; echo 0;} | bc)
fallocate -l "$size" out &&
  find . -maxdepth 1 -type f -name 'input_file*' -print0 |
  sort -z | xargs -r0 cat 1<> out

Еще одним преимуществом является то, что если не хватает свободного места, копия не будет предприниматься.

Если включено btrfs, вы можете copy --reflink=alwaysпервый файл (который подразумевает отсутствие копирования данных и, следовательно, будет почти мгновенным), и добавить остальные. Если есть 10000 файлов, это, вероятно, не будет иметь большого значения, если только первый файл не очень большой.

Существует обобщающий API для повторного копирования всех файлов ( BTRFS_IOC_CLONE_RANGE ioctl), но я не смог найти никакой утилиты, предоставляющей этот API, поэтому вам придется делать это на C ( pythonили на других языках, если они могут вызывать произвольные ioctls). ,

Если исходные файлы редки или имеют большие последовательности символов NUL, вы можете создать разреженный выходной файл (экономя время и дисковое пространство) с помощью (в системах GNU):

find . -maxdepth 1 -type f -name 'input_file*' -print0 |
  sort -z | xargs -r0 cat | cp --sparse=always /dev/stdin out
Стефан Шазелас
источник
1
@XTian, ​​нет, это не должно быть ни, >ни >>, но, 1<>как я уже сказал, чтобы записать в файл.
Стефан Шазелас
5
@grebneke, <>это стандартный оператор перенаправления чтения / записи Bourne / POSIX. Подробности смотрите в руководстве по вашей оболочке или в спецификации POSIX . Значение по умолчанию fdявляется 0для <>оператора ( <>коротко для 0<>, как <коротко для 0<и >коротких для 1>), поэтому вам нужно 1явно перенаправлять стандартный вывод. Здесь не так много, что нам нужно read + write ( O_RDWR), но мы не хотим O_TRUNC(как в >), который бы освободил то, что мы только что выделили.
Стефан Шазелас
1
@grebneke, unix.stackexchange.com/search?q=user%3A22565+%22%3C%3E%22 даст вам несколько. КШ93 имеет операторы поиска BTW, и вы можете искать вперед с ddпомощью или через чтение.
Стефан Шазелас
1
@StephaneChazelas - большое спасибо, ваша помощь и знания высоко ценятся!
Гребнеке
1
Я не убежден, что будет много случаев, когда fallocateбудут сводиться на нет дополнительные издержки find, даже если это будет быстрее во второй раз. btrfsконечно, открывает некоторые интересные возможности, хотя.
Грэм