Kopyalamadan birbirlerine büyük dosyalar ekleyin


41

Her biri yaklaşık 10G olan 5 büyük dosya (dosya1, dosya2, .. dosya5) ve diskte oldukça düşük boş alan kalıyor ve tüm bu dosyaları bir araya getirmem gerekiyor. Orijinal dosyaları tutmaya gerek yok, sadece sonuncusu.

Her zamanki birleştirme, catdosyalar için sırayla gerçekleşir file2.. file5:

cat file2 >> file1 ; rm file2

Ne yazık ki bu yol, sahip olmadığım en az 10G boş alan gerektiriyor. Dosyaları gerçek kopyalanmadan birleştirmenin bir yolu var mı, ancak dosya sistemine bir şekilde orijinal dosyanın1 sonunda bitmediğini ve dosya2 başlangıcında devam ettiğini söyleyin.

ps. eğer önemli olan dosya sistemi ext4'tür.


2
Bir çözüm görmek isterdim, ancak doğrudan dosya sistemiyle uğraşmadan mümkün olmadığını sanıyorum.
Kevin,

1
Neden bu kadar büyük tek bir fiziksel dosyaya ihtiyacınız var? Soruyorum çünkü belki birleştirmek istemeyebilirsiniz - ki şu anki cevapların gösterdiği gibi, oldukça rahatsız edici.
liori

6
@rush: o zaman bu cevap yardımcı olabilir: serverfault.com/a/487692/16081
liori

1
Cihaz eşleştiriciye alternatif, daha az verimli, ancak parçalanması kolay bir cihazla sonuçlanması ve uygulanması kolaydır ve uzaktaki bir makineden kullanılabilir "multi" modunu kullanmaktır nbd-server.
Stéphane Chazelas

1
Bunun havalı olması gerektiğini düşündüğümde beni hep aptal diye çağırıyorlar.
n611x007

Yanıtlar:


19

AFAIK başından bir dosyayı (bu standart araçlar için de geçerli ama syscall düzeyi için olabilir kesecek şekilde (maalesef) mümkün değildir burada bakınız ). Ancak biraz karmaşıklık ekleyerek normal kesmeyi kullanabilirsiniz (seyrek dosyalar ile birlikte): Aradaki tüm verileri yazmadan hedef dosyanın sonuna yazabilirsiniz.

İlk önce her iki dosyanın da tam olarak 5GiB (5120 MiB) olduğunu ve bir seferde 100 MiB taşımak istediğinizi varsayalım. Oluşan bir döngü yürütmek

  1. kaynak dosyanın sonundan hedef dosyanın sonuna bir bloğun kopyalanması (tüketilen disk alanını artırarak)
  2. kaynak dosyayı bir blok keserek (disk alanını boşaltma)

    for((i=5119;i>=0;i--)); do
      dd if=sourcefile of=targetfile bs=1M skip="$i" seek="$i" count=1
      dd if=/dev/zero of=sourcefile bs=1M count=0 seek="$i"
    done
    

Ama önce daha küçük test dosyalarını deneyin, lütfen ...

Muhtemelen dosyalar ne boyutta ne de blok boyutunun katları değildir. Bu durumda ofsetlerin hesaplanması daha karmaşık hale gelir. seek_bytesve skip_bytessonra kullanılmalıdır.

Eğer gitmek istediğiniz ancak ayrıntılar için yardıma ihtiyaç duyuyorsanız, tekrar sorun.

Uyarı

ddBlok büyüklüğüne bağlı olarak, ortaya çıkan dosya bir parçalanma kabusu olacaktır.


Bu dosyaları birleştirmek için en kabul edilebilir yol gibi görünüyor. Tavsiyen için teşekkürler.
acele

3
eğer seyrek bir dosya desteği yoksa, ikinci dosyayı yerinde blok olarak tersine çevirebilir ve son bloğu kaldırabilir ve ikinci dosyaya ekleyebilirsiniz
cırcır ucube 0

1
Bunu kendim denemedim (ne yapmak istersem), ancak seann.herdejurgen.com/resume/samag.com/html/v09/i08/a9_l1.htm bu algoritmayı uyguladığını iddia eden bir Perl betiğidir.
zwol

16

Dosyaları tek bir dosyada bir araya getirmek yerine, programınız birden fazla dosyayı işleyemiyorsa, tek bir dosyayı adlandırılmış bir kanalla simüle edebilirsiniz.

mkfifo /tmp/file
cat file* >/tmp/file &
blahblah /tmp/file
rm /tmp/file

Hauke'nin önerdiği gibi, losetup / dmsetup de çalışabilir. Hızlı bir deney; 'File1..file4' dosyasını oluşturdum ve biraz çaba sarfettim:

for i in file*;do losetup -f ~/$i;done

numchunks=3
for i in `seq 0 $numchunks`; do
        sizeinsectors=$((`ls -l file$i | awk '{print $5}'`/512))
        startsector=$(($i*$sizeinsectors))
        echo "$startsector $sizeinsectors linear /dev/loop$i 0"
done | dmsetup create joined

Ardından, / dev / dm-0, içeriğiniz olarak dosyanızı içeren bir sanal blok aygıtı içerir.

Bunu iyi test etmedim.

Başka bir düzenleme: Dosya boyutu 512 ile eşit şekilde bölünebilir olmalıdır, aksi halde bazı verileri kaybedersiniz. Eğer öyleyse, o zaman iyisin. Gördüğüm kadarıyla aşağıda da dikkat çekti.


Bu dosyayı bir kez okumak harika bir fikir, ne yazık ki 5/5 üzerine atlamak mümkün değil, değil mi?
acele

7
@ rush Üstün alternatif, her dosyaya bir döngü cihazı koymak ve onları dmsetupsanal bir engelleme aygıtı ile birleştirmek (normal arama işlemlerine izin veren ancak eklenmeyen veya kesilmeyen ) olabilir. İlk dosyanın boyutu 512'nin katı değilse, tamamlanmamış olan son bölümü ve ilk baytı ikinci dosyadan (toplam 512) üçüncü bir dosyaya kopyalamanız gerekir. İkinci dosya için döngü cihazı --offsetsonra gerekir .
Hauke ​​Laging

zarif çözümler +1 ayrıca, ilk dosyanın boyutu 512 katı değilse sorunu gidermek için bir yol öneren Hauke ​​Laging'e
Olivier Dulac

9

Verileri, sahip olduğunuz en fazla boş alan miktarı kadar büyük olan demetlere kopyalayan bir şeyler yazmanız gerekir. Bu şekilde çalışması gerekir:

  • Veri bloğunu okuyun file2( pread()okumadan önce doğru yere bakarak arayarak).
  • Bloğu şuna ekle file1.
  • fcntl(F_FREESP)Alandan ayırmak için kullanın file2.
  • Tekrar et

1
Biliyorum ... ama kod yazmayı içermeyen bir yol düşünemedim ve yazdığım şeyin hiçbir şey yazmamaktan daha iyi olduğunu düşündüm. Sonundan başlayarak zekice bir numara olduğunu düşünmedim!
Celada

Sizinki de, en baştan başlamadan işe yaramazdı, değil mi?
Hauke ​​Laging

Hayır, fcntl(F_FREESP)dosyanın belirli bir bayt aralığıyla ilişkili boşluğu boşalttığı için baştan işe yarar (onu seyrekleştirir).
Celada

Bu oldukça havalı. Ancak çok yeni bir özellik gibi görünüyor. fcntlAdam sayfamda bahsedilmiyor (2012-04-15).
Hauke ​​Laging

4
@HaukeLaging F_FREESP Solaris'dir. Linux'ta (2.6.38'den beri), fallocatesistem çağrısının FALLOC_FL_PUNCH_HOLE bayrağı . Fallocate yardımcı programının daha yeni sürümleri util-linuxbuna bir arayüze sahip.
Stéphane Chazelas

0

Bunun senin istediğinden daha fazla geçici bir çözüm olduğunu biliyorum, ama senin sorununun çaresine bakardı (ve küçük parçalanma veya baş çizme ile):

#step 1
mount /path/to/... /the/new/fs #mount a new filesystem (from NFS? or an external usb disk?)

ve sonra

#step 2:
cat file* > /the/new/fs/fullfile

veya, sıkıştırmanın yardımcı olacağını düşünüyorsanız:

#step 2 (alternate):
cat file* | gzip -c - > /the/new/fs/fullfile.gz

Sonra (ve SADECE sonra), sonunda

#step 3:
rm file*
mv /the/new/fs/fullfile  .   #of fullfile.gz if you compressed it

Ne yazık ki harici usb disk fiziksel erişim gerektirir ve nfs ek donanım gerektirir ve bende hiçbir şey yok. Neyse, teşekkürler. =)
acele

Öyle olacağını düşündüm ... Rob Bos'un cevabı en iyi seçenek gibi görünüyor (kopyaları keserken veri kaybetme riski olmadan ve aynı zamanda FS sınırlamalarına çarpmadan da)
Olivier Dulac
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.