A maneira mais rápida de concatenar arquivos

23

Eu tenho 10k + arquivos, totalizando mais de 20GB, e preciso concatenar em um arquivo.

Existe uma maneira mais rápida do que

cat input_file* >> out

?

O modo preferido seria um comando bash, o Python é aceitável também se não for consideravelmente mais lento.

    
por FAS 05.03.2014 / 13:50

2 respostas

29

Não, o gato é certamente a melhor maneira de fazer isso. Por que usar python quando já existe um programa escrito em C para esse propósito? No entanto, você pode querer considerar o uso de xargs caso o comprimento da linha de comando exceda ARG_MAX e você precise de mais de um cat . Usando ferramentas GNU, isso é equivalente ao que você já tem:

find . -maxdepth 1 -type f -name 'input_file*' -print0 |
  sort -z |
  xargs -0 cat -- >>out
    
por 05.03.2014 / 14:04
21

A alocação do espaço para o arquivo de saída primeiro pode melhorar a velocidade geral, pois o sistema não precisará atualizar a alocação para cada gravação.

Por exemplo, se no 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

Outro benefício é que, se não houver espaço livre suficiente, a cópia não será tentada.

Se em btrfs , você poderia copy --reflink=always o primeiro arquivo (o que implica em nenhuma cópia de dados e, portanto, seria quase instantâneo), e acrescente o resto. Se houver 10000 arquivos, isso provavelmente não fará muita diferença, a menos que o primeiro arquivo seja muito grande.

Há uma API para generalizar isso para ref copiar todos os arquivos (o BTRFS_IOC_CLONE_RANGE ioctl ), mas não consegui encontrar nenhum utilitário expondo essa API, então você teria que fazer isso em C (ou python ou outros idiomas, desde que possam chamar arbitrariamente ioctl s).

Se os arquivos de origem forem esparsos ou tiverem grandes seqüências de caracteres NUL, você poderá criar um arquivo de saída esparso (economizando tempo e espaço em disco) com (nos sistemas GNU):

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