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.