Existem 5 arquivos enormes (arquivo1, arquivo2, .. arquivo5) com cerca de 10G cada e um espaço livre extremamente baixo disponível no disco e preciso concatenar todos esses arquivos em um. Não há necessidade de manter os arquivos originais, apenas o final.
A concatenação usual está cat
em sequência nos arquivos file2
.. file5
:
cat file2 >> file1 ; rm file2
Infelizmente, esse caminho requer um espaço livre de pelo menos 10G que não tenho. Existe uma maneira de concatenar arquivos sem copiá-lo de verdade, mas diga ao sistema de arquivos que o arquivo1 não termina no final do arquivo1 original e continua no início do arquivo2?
ps. sistema de arquivos é ext4, se isso importa.
filesystems
files
pressa
fonte
fonte
nbd-server
.Respostas:
AFAIK (infelizmente) não é possível truncar um arquivo desde o início (isso pode ser verdade para as ferramentas padrão, mas para o nível de syscall, veja aqui ). Mas, com a adição de alguma complexidade, você pode usar o truncamento normal (junto com arquivos esparsos): Você pode gravar no final do arquivo de destino sem ter gravado todos os dados no meio.
Vamos supor primeiro que os dois arquivos sejam exatamente 5GiB (5120 MiB) e que você deseja mover 100 MiB por vez. Você executa um loop que consiste em
truncar o arquivo de origem em um bloco (liberando espaço em disco)
Mas tente primeiro com arquivos de teste menores primeiro, por favor ...
Provavelmente, os arquivos não têm o mesmo tamanho nem múltiplos do tamanho do bloco. Nesse caso, o cálculo das compensações se torna mais complicado.
seek_bytes
eskip_bytes
deve ser usado então.Se esse é o caminho que você deseja seguir, mas precisa de ajuda para obter detalhes, pergunte novamente.
Atenção
Dependendo do
dd
tamanho do bloco, o arquivo resultante será um pesadelo de fragmentação.fonte
Em vez de reunir os arquivos em um arquivo, talvez simule um único arquivo com um pipe nomeado, se o seu programa não puder lidar com vários arquivos.
Como Hauke sugere, losetup / dmsetup também pode funcionar. Um experimento rápido; Criei 'file1..file4' e, com um pouco de esforço, fiz:
Em seguida, / dev / dm-0 contém um dispositivo de bloco virtual com seu arquivo como conteúdo.
Eu não testei isso bem.
Outra edição: o tamanho do arquivo deve ser divisível uniformemente por 512 ou você perderá alguns dados. Se for, então você é bom. Vejo que ele também observou isso abaixo.
fonte
dmsetup
de um dispositivo de bloco virtual (que permite operações normais de busca, mas nem anexa nem truncada). Se o tamanho do primeiro arquivo não for múltiplo de 512, copie o último setor incompleto e os primeiros bytes do segundo arquivo (na soma 512) para um terceiro arquivo. O dispositivo de loop para o segundo arquivo precisaria--offset
então.Você precisará escrever algo que copie dados em grupos que sejam no máximo tão grandes quanto a quantidade de espaço livre disponível. Deve funcionar assim:
file2
(usandopread()
procurando antes da leitura no local correto).file1
.fcntl(F_FREESP)
para desalocar o espaço defile2
.fonte
fcntl(F_FREESP)
que libera o espaço associado a um determinado intervalo de bytes do arquivo (o torna escasso).fcntl
página do manual (15-04-2012).fallocate
. As versões mais recentes do utilitário fallocateutil-linux
têm uma interface para isso.Eu sei que é mais uma solução alternativa do que você solicitou, mas isso resolveria o seu problema (e com pouca fragmentação ou arranhão na cabeça):
e depois
ou, se você acha que a compactação ajudaria:
Então (e SOMENTE então), finalmente
fonte