Birçok benzer boyutlu dosyayı boyut sınırına sahip birden çok arşive tar.gz nasıl


11

Ubuntu 16.04'deyim.

Metin dosyaları bir sürü (neredeyse 12k) ile bir klasör var. Hepsini .tar.gzyüklemeleri kabul eden bir web sitesine yüklemeniz ve daha sonra bunları otomatik olarak açmanız gerekiyor, ancak dosya başına 10MB (10000KB) sınırına sahip (bu yüzden özellikle her dosyanın kendi sıkıştırması gerekiyor). Ben ise tar.gzbütün bu dosyalar sonuç dosyası 72MB hakkında taşımaktadır.

Ne yapmak istiyorum .tar.gzher biri boyut / boyut (kesinlikle) 10000KB daha küçük sekiz dosya oluşturmaktır .

Alternatif olarak, yukarıdaki tüm dosyaların yaklaşık olarak aynı boyuta sahip olduğu varsayılabilir, bu yüzden .tar.gzher biri az çok aynı miktarda dosya içeren sekiz dosya oluşturmak istiyorum .

Bu iki görevden herhangi birini nasıl yapabilirim?

GUI, CLI veya komut dosyası içeren bir çözümle mükemmelim. Burada hız aramıyorum, sadece buna ihtiyacım var.


Muhtemelen sahip olduğunuz 12k dosyaların adlarında desen veya tekrarlanan karakterler olacaktır. tarBelli bir desenle başlayan tüm dosyaları, hepsine sahip olana kadar ekleyerek muhtemelen bunları yapabilirsiniz . Bu kolayca yazılabilir, ancak boyutun ihtiyacınız olan 9 MB'den daha düşük olacağını garanti etmez. Bununla birlikte, çok büyük olan dosyaların boyutunu daha da bölerek manuel olarak ayarlayabilirsiniz.
Juan Antonio

Yanıtlar:


9

Tamamen patchwork ve olduğu gibi hızlı, kaba bir taslak, ancak 3000 dosya içeren bir dizinde test edildi, aşağıdaki komut dosyası son derece hızlı bir iş yaptı:

#!/usr/bin/env python3
import subprocess
import os
import sys

splitinto = 2

dr = sys.argv[1]
os.chdir(dr)

files = os.listdir(dr)
n_files = len(files)
size = n_files // splitinto

def compress(tar, files):
    command = ["tar", "-zcvf", "tarfile" + str(tar) + ".tar.gz", "-T", "-", "--null"]
    proc = subprocess.Popen(command, stdin=subprocess.PIPE)
    with proc:
        proc.stdin.write(b'\0'.join(map(str.encode, files)))
        proc.stdin.write(b'\0')
    if proc.returncode:
        sys.exit(proc.returncode)

sub = []; tar = 1
for f in files:
    sub.append(f)
    if len(sub) == size:
        compress(tar, sub)
        sub = []; tar += 1

if sub:
    # taking care of left
    compress(tar, sub)

Nasıl kullanılır

  • Boş bir dosya olarak kaydedin compress_split.py
  • Kafa bölümünde, sıkıştırılacak dosya sayısını ayarlayın. Uygulamada, geri kalan birkaç "kalan" ile ilgilenmek için her zaman bir tane daha olacaktır.
  • Bağımsız değişken olarak dosyalarınızla dizinde çalıştırın:

    python3 /path/tocompress_split.py /directory/with/files/tocompress

numaralı .tar.gzdosyalar dosyaların bulunduğu dizinde oluşturulur.

açıklama

Senaryo:

  • dizindeki tüm dosyaları listeler
  • tar dosyasına yol bilgisi eklenmesini önlemek için cd'ler dizine eklenir
  • dosya listesini okur, bunları küme bölümüne göre gruplandırır
  • alt grubu / grupları numaralı dosyalara sıkıştırır

DÜZENLE

MB cinsinden boyuta göre otomatik olarak parçalar oluşturun

Daha karmaşık olan ise, parçaların maksimum boyutunu (mb cinsinden) (ikinci) bir argüman olarak kullanmaktır. Aşağıdaki kodda, parçalar eşik değere ulaşır ulaşmaz sıkıştırılmış bir dosyaya yazılır.

Komut dosyası, eşiği aşan parçalar tarafından tetiklendiğinden, bu yalnızca (tüm) dosyaların boyutu yığın boyutundan önemli ölçüde küçükse çalışır.

Senaryo:

#!/usr/bin/env python3
import subprocess
import os
import sys

dr = sys.argv[1]
chunksize = float(sys.argv[2])
os.chdir(dr)

files = os.listdir(dr)
n_files = len(files)

def compress(tar, files):
    command = ["tar", "-zcvf", "tarfile" + str(tar) + ".tar.gz", "-T", "-", "--null"]
    proc = subprocess.Popen(command, stdin=subprocess.PIPE)
    with proc:
        proc.stdin.write(b'\0'.join(map(str.encode, files)))
        proc.stdin.write(b'\0')
    if proc.returncode:
        sys.exit(proc.returncode)

sub = []; tar = 1; subsize = 0
for f in files:
    sub.append(f)
    subsize = subsize + (os.path.getsize(f)/1000000)
    if subsize >= chunksize:
        compress(tar, sub)
        sub = []; tar += 1; subsize = 0

if sub:
    # taking care of left
    compress(tar, sub)

Koşmak:

python3 /path/tocompress_split.py /directory/with/files/tocompress chunksize

... chunksize, tar komutu için girdi boyutudur .

Buna, @DavidFoerster tarafından önerilen iyileştirmeler dahildir. Teşekkürler çok !


@ dadexix86 rica ederim!
Jacob Vlijm

Kabuk istilasından kurtuldum ve doğrudan bir tartışma listesi kullandım. Yine de, büyük argüman listeleri sorunlu olabilir tarve standart girdi akışında dosya listesini sağlayarak çağrıyı daha da geliştirmeye çalışacağım .
David Foerster

Merhaba @ DavidFoerster, içgörülerine güveniyorum, ama avantajı nedir?
Jacob Vlijm

Çoğu çalışma zamanı ortamında, binlerce dosya üzerinde çalışırken hızlı bir şekilde erişeceğiniz bir komutun bağımsız değişken dizelerinin toplam uzunluğu (yumuşak ve sert) sınırı vardır. Bu nedenle tar, standart girdiye eklenecek (veya çıkarılacak) dosyaları uygun bir seçenekle belirtmenize izin verir.
David Foerster

@DavidFoerster bir sorun olsa da, ikincisi artık çalışmıyor. Aslında ikisi de ...
Jacob Vlijm

6

Saf bir kabuk yaklaşımı:

files=(*); 
num=$((${#files[@]}/8));
k=1
for ((i=0; i<${#files[@]}; i+=$num)); do 
    tar cvzf files$k.tgz -- "${files[@]:$i:$num}"
    ((k++))
done

açıklama

  • files=(*): dizinin içindeki dosyaların listesini kaydedin (varsa dizinler, files=(*.txt)yalnızca txtuzantıya sahip olanları almak için değiştirin ) $files.
  • num=$((${#files[@]}/8));: ${#files[@]}dizideki öğelerin sayısıdır $files. $(( ))Aritmetik yapmanın Bash'in (sınırlı) bir yoldur. Bu nedenle, bu komut $numdosya sayısına 8'e bölünür.
  • k=1 : sadece tarball'ları adlandırmak için bir sayaç.
  • for ((i=0; i<${#files[@]}; i+=$num)); do: dizinin değerleri üzerinden yineleme. öğesinde (dizinin ilk öğesi) $ibaşlatılır 0ve artırılır $num. Bu, tüm öğelerden (dosyalar) geçene kadar devam eder.
  • tar cvzf files$i.tgz -- ${files[@]:$i:$num}: bash içinde, kullanarak bir dizi dilim (bir dizinin bir parçası) alabilirsiniz ${array[@]:start:length}, Yani ${array[@]:2:3}ikinci itibaren başlayarak üç öğe dönecektir. Burada, şu anki değerinden başlayan $ive $numelementler uzun olan bir dilim alıyoruz . --Bir başlayabilir herhangi dosya adlarına durumunda gereklidir -.
  • ((k++)) : artış $k

Güzel! İlk kez bash dizi indeksi aralıklarının pratik bir kullanımını gördüm.
Joe

Çok temiz ve özlü. Bana göre, Python çözümlerinden daha anlaşılır olsa da, her ikisi de oldukça iyi. Hepsinin performansla nasıl karşılaştırıldığını merak ediyor musunuz?
DocSalvager
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.