it-swarm.com.de

So tarieren Sie viele Dateien ähnlicher Größe in mehrere Archive mit einer Größenbeschränkung

Ich bin auf Ubuntu 16.04.

Ich habe einen Ordner mit vielen Textdateien (fast 12k). Ich muss sie alle auf eine Website hochladen, die das Hochladen und anschließende automatische Dekomprimieren von .tar.gz akzeptiert, aber eine Beschränkung von 10 MB (10000 KB) pro Datei hat (daher muss insbesondere jede Datei für sich dekomprimiert werden). Wenn ich tar.gz alle diese Dateien, ist die resultierende Datei von etwa 72 MB.

Was ich tun möchte, ist, acht .tar.gz -Dateien zu erstellen, wobei jede Größe/Dimension (streng) kleiner als 10000 KB ist.

Alternativ kann man davon ausgehen, dass alle oben genannten Dateien ungefähr die gleiche Größe haben. Daher möchte ich acht .tar.gz -Dateien mit jeweils mehr oder weniger der gleichen Anzahl von Dateien erstellen.

Wie kann ich eine dieser beiden Aufgaben ausführen?

Ich bin vollkommen in Ordnung mit einer Lösung, die GUI, CLI oder Scripting beinhaltet. Ich suche hier keine Geschwindigkeit, ich muss es einfach machen.

11
dadexix86

Totally Patchwork und eine schnelle, grobe Skizze wie es ist, aber getestet auf einem Verzeichnis mit 3000 Dateien, hat das Skript unten einen extrem schnellen Job gemacht:

#!/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)

Wie benutzt man

  • Speichere es als compress_split.py in eine leere Datei
  • Legen Sie im Abschnitt head die Anzahl der Dateien fest, in die komprimiert werden soll. In der Praxis wird es immer einen mehr geben, der sich um die verbleibenden "Reste" kümmert.
  • Führen Sie es mit dem Verzeichnis mit Ihren Dateien als Argument aus:

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

nummerierte .tar.gz -Dateien werden in demselben Verzeichnis erstellt, in dem sich die Dateien befinden.

Erläuterung

Das Drehbuch:

  • listet alle Dateien im Verzeichnis auf
  • cd's in das verzeichnis, um das hinzufügen der pfadinformationen zur tar datei zu verhindern
  • liest die Dateiliste durch und gruppiert sie nach der eingestellten Unterteilung
  • komprimiert die Untergruppe (n) in nummerierte Dateien

BEARBEITEN

Erstellen Sie automatisch Blöcke nach Größe in MB

Anspruchsvoller ist es, die maximale Größe (in MB) der Chunks als (zweites) Argument zu verwenden. Im folgenden Skript werden die Chunks in eine komprimierte Datei geschrieben, sobald der Chunk den Schwellenwert erreicht (überschreitet).

Da das Skript von den Chunks ausgelöst wird und den Schwellenwert überschreitet, funktioniert dies nur, wenn die Größe (aller) Dateien wesentlich kleiner als die Chunk-Größe ist.

Das Drehbuch:

#!/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)

Zu rennen:

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

... wobei chunksize die Größe von Eingabe für den Befehl tar ist.

In dieser sind die von @DavidFoerster vorgeschlagenen Verbesserungen enthalten. Danke viel!

9
Jacob Vlijm

Ein reiner Shell-Ansatz:

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

Erläuterung

  • files=(*): Speichert die Liste der Dateien (auch Verzeichnisse, falls vorhanden, wechselt zu files=(*.txt), um nur Objekte mit der Erweiterung txt zu erhalten) im Array $files.
  • num=$((${#files[@]}/8));: ${#files[@]} ist die Anzahl der Elemente im Array $files. Die $(( )) ist die (eingeschränkte) Art, wie Bash rechnet. Dieser Befehl setzt also $num auf die Anzahl der Dateien geteilt durch 8.
  • k=1: Nur ein Zähler, um die Tarballs zu benennen.
  • for ((i=0; i<${#files[@]}; i+=$num)); do: Durchlaufen Sie die Werte des Arrays. $i wird bei 0 (dem ersten Element des Arrays) initialisiert und um $num erhöht. Dies geht so lange weiter, bis wir alle Elemente (Dateien) durchgegangen sind.
  • tar cvzf files$i.tgz -- ${files[@]:$i:$num}: In Bash können Sie mit ${array[@]:start:length} einen Array-Slice (Teil eines Arrays) abrufen. ${array[@]:2:3} gibt also drei Elemente ab dem zweiten zurück. Hier nehmen wir ein Slice, das mit dem aktuellen Wert von $i beginnt und $num Elemente lang ist. Der -- wird benötigt, wenn einer Ihrer Dateinamen mit einem - beginnen kann.
  • ((k++)): Inkrementiere $k
6
terdon