Najszybszy sposób na łączenie plików


25

Mam ponad 10 000 plików o łącznej wielkości ponad 20 GB, które muszę połączyć w jeden plik.

Czy jest szybszy sposób niż

cat input_file* >> out

?

Preferowanym sposobem byłoby polecenie bash, Python jest również akceptowalny, jeśli nie znacznie wolniejszy.


Zaktualizowałem moją odpowiedź, findnie sortuje plików tak samo jak glob powłoki.
Graeme

5
Wszystkie (rozsądne) rozwiązania będą miały tutaj równoważną prędkość, ponieważ czas będzie wynosił 99% systemowych I / O.
goldilocks


3
Zastanawiasz się nad zapisaniem skonkatowanego pliku na innym dysku niż ten, z którego czytasz.
Luis

1
Będzie szybciej, jeśli outznajduje się na innym dysku.

Odpowiedzi:


30

Nie, kot jest z pewnością najlepszym sposobem na zrobienie tego. Po co używać Pythona, jeśli w tym celu jest już napisany program w C? Możesz jednak rozważyć użycie xargsna wypadek, gdyby długość wiersza poleceń przekroczyła ARG_MAXi potrzebujesz więcej niż jednego cat. Przy użyciu narzędzi GNU jest to równoważne z tym, co już masz:

find . -maxdepth 1 -type f -name 'input_file*' -print0 |
  sort -z |
  xargs -0 cat -- >>out

1
Czy możesz w tym przypadku zapewnić, że twoje pliki zostaną odczytane w kolejności?
Kiwy

1
Tak, ponieważ dane wyjściowe findsą przesyłane strumieniowo sort. Bez tego pliki byłyby wyświetlane w dowolnej kolejności (zdefiniowanej przez system plików, którym może być kolejność tworzenia plików).
scai

@scai Przepraszam, przepraszam, z pewnym rodzajem to całkiem oczywiste
Kiwy

1
@ Kiwi, jedyny przypadek, jaki widzę to to, że ustawienia regionalne nie są poprawnie ustawione w środowisku, a następnie sortowanie może zachowywać się inaczej niż bashglob. W przeciwnym razie nie widzę przypadków, w których zachowywałbym się xargslub catnie zachowywałbym zgodnie z oczekiwaniami.
Graeme

3
@MarcvanLeeuwen, xargszadzwoni tak, catjak to konieczne, aby uniknąć błędu E2BIG execve (2).
Stéphane Chazelas

21

Przydzielenie najpierw miejsca na plik wyjściowy może poprawić ogólną szybkość, ponieważ system nie będzie musiał aktualizować przydziału dla każdego zapisu.

Na przykład, jeśli w systemie 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

Kolejną korzyścią jest to, że jeśli nie ma wystarczającej ilości wolnego miejsca, kopia nie zostanie podjęta.

Jeśli jest włączony btrfs, możesz copy --reflink=alwayspobrać pierwszy plik (co oznacza brak kopiowania danych i dlatego byłby prawie natychmiastowy), a resztę dołączyć. Jeśli jest 10000 plików, prawdopodobnie nie zrobi to dużej różnicy, chyba że pierwszy plik jest bardzo duży.

Istnieje interfejs API do uogólnienia tego, aby ponownie skopiować wszystkie pliki ( BTRFS_IOC_CLONE_RANGE ioctl), ale nie mogłem znaleźć żadnego narzędzia udostępniającego ten interfejs API, więc musiałbyś to zrobić w C ( pythonlub w innych językach, pod warunkiem, że mogą wywoływać dowolne ioctl) .

Jeśli pliki źródłowe są rzadkie lub mają duże ciągi znaków NUL, możesz utworzyć rzadki plik wyjściowy (oszczędzając czas i miejsce na dysku) za pomocą (w systemach GNU):

find . -maxdepth 1 -type f -name 'input_file*' -print0 |
  sort -z | xargs -r0 cat | cp --sparse=always /dev/stdin out

1
@XTian, ​​nie, to nie powinno być >ani >>, ale, 1<>jak już powiedziałem, aby zapisać do pliku.
Stéphane Chazelas

5
@grebneke, <>jest standardowym operatorem przekierowania odczytu i zapisu Bourne / POSIX. Szczegółowe informacje można znaleźć w instrukcji obsługi powłoki lub specyfikacji POSIX . Domyślnie fdjest 0to <>operator ( <>jest skrótem 0<>, podobnie jak <skrótem 0<i >skrótem 1>), więc musisz 1jawnie przekierować standardowe wyjście. Tutaj nie tyle potrzebujemy read + write ( O_RDWR), ale nie chcemy O_TRUNC(jak w >), aby cofnęli przydzielenie tego, co właśnie przydzieliliśmy.
Stéphane Chazelas

1
@grebneke, unix.stackexchange.com/search?q=user%3A22565+%22%3C%3E%22 da ci kilka. ksh93 ma operatorów wyszukiwania BTW, i możesz wyszukiwać dalej, ddczytając lub czytając.
Stéphane Chazelas

1
@StephaneChazelas - wielkie dzięki, twoja pomoc i wiedza są bardzo cenione!
grebneke

1
Nie jestem przekonany, że będzie wiele przypadków, w których fallocateneguje się dodatkowe koszty find, mimo że będzie to szybsze za drugim razem. btrfsz pewnością otwiera jednak kilka interesujących możliwości.
Graeme
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.