Wie kann ich eine Datei unter Linux direkt komprimieren, ohne zusätzlichen Speicherplatz zu belegen?

20

Ich habe ein 100-GB-Laufwerk mit einer 95-GB-Datei. Ich muss Speicherplatz auf dem Laufwerk freigeben (und das Übertragen der Datei vom Laufwerk ist derzeit keine Option). Die Datei würde gut mit gzipoder bz2oder was auch immer komprimiert , aber alle diese Programme schreiben die komprimierte Datei in eine separate Datei. Ich habe nicht genug freien Speicherplatz dafür.

Gibt es eine Möglichkeit, die Datei mit Standardkomprimierungstools oder anderen Unix-Dienstprogrammen zu komprimieren, ohne zusätzlichen Speicherplatz zu belegen (oder zumindest einen minimalen zusätzlichen Speicherplatz)? Ich stelle mir etwas vor, das einen Teil der Datei gleichzeitig komprimiert und die Ergebnisse direkt über die Datei schreibt. Mir ist klar, dass dies riskant wäre, da die Datei beschädigt würde, wenn die Komprimierung unterbrochen würde, aber ich glaube nicht, dass ich eine Wahl habe.

Lee
quelle
Eine letzte Option, die wir an meinem alten Ort verwendet haben, war, irgendwo ein Verzeichnis zu haben, das eine ganze Reihe von 1G-Dateien mit Müll enthielt. Dann, wenn Sie in eine Klemme geraten, könnten Sie einige davon entfernen, um Ihnen ein bisschen Notraum zu geben.

Antworten:

13

Dies ist ein Proof-of-Concept-Bash-Einzeiler, aber es sollte Ihnen den Einstieg erleichtern. Benutzung auf eigene Gefahr.

truncate -s `gzip -c file | dd of=file conv=notrunc 2>&1 | sed -n '$ s/ .*$// p'` file
mv file file.gz

Dies funktioniert, indem gz-Daten an einen dd-Prozess weitergeleitet werden, der sie in dieselbe Datei zurückschreibt. Nach Abschluss wird die Datei auf die Größe der gz-Ausgabe gekürzt.

Dies setzt voraus, dass die letzte Zeile der Ausgabe von dd übereinstimmt:

4307 Byte (4,3 kB) kopiert, 2,5855e-05 s, 167 MB / s

Wobei das erste Feld eine Ganzzahl von geschriebenen Bytes ist. Auf diese Größe muss die Datei gekürzt werden. Ich bin nicht zu 100% sicher, dass das Ausgabeformat immer dasselbe ist.

user710307
quelle
Schicker Trick. Können Sie erklären, warum dies conv=notruncnotwendig ist?
sleske
Vielleicht ist es nicht. gzip -c file | dd of=filescheint genauso gut zu funktionieren.
user710307
1
Die Leute bei der verknüpften Frage haben es versucht (und ich habe es auch versucht); es funktioniert im Allgemeinen nicht. Scheint, dass es nur für sehr kleine Dateien funktioniert - möglicherweise, weil gzip eine kleine Datei vor dem Komprimieren in den Arbeitsspeicher liest. Bei großen Dateien (einige MB) funktioniert dies nicht, auch wenn sie komprimierbar sind.
sleske 18.01.12
3
Ja. Also ist conv = notrunc notwendig.
user710307
1
Ist es nicht möglich, dass das Komprimierungsprogramm (z. B. gzip) zu irgendeinem Zeitpunkt mehr Header- und Datenbytes als die ursprünglichen Datenbytes schreibt und so einige Teile der Datei überschreibt? Ich denke, das hängt vom gewählten Komprimierungsprogramm ab. Hat jemand eine Idee, wie dies verhindert werden kann oder wie (unwahrscheinlich) es ist?
Daniel Böhmer
7

Es ist nicht so sehr das gzipund bzip2überschreibt das Original. Stattdessen schreiben sie die komprimierten Daten als neue Datei auf die Festplatte. Wenn dieser Vorgang erfolgreich ist, heben sie die Verknüpfung der ursprünglichen unkomprimierten Datei auf.

Wenn Sie über ausreichend RAM verfügen, können Sie ein Skript schreiben, um die Dateien in einem tmpfsDateisystem vorübergehend zu komprimieren. Entfernen Sie dann das Original auf der Festplatte und ersetzen Sie es durch die komprimierte Version. Vielleicht so etwas:

# some distributions mount /dev/shm as tmpfs; replace with bzip2 if you prefer
if gzip -q9c /full/disk/somefile > /dev/shm/somefile.gz
then
    rm -f /full/disk/somefile && mv -i /dev/shm/somefile.gz /full/disk
fi

Denken Sie nur an Ihre Speichernutzung, da tmpfses sich im Wesentlichen um eine RAM-Disk handelt. Eine große Ausgabedatei kann das System leicht aushungern lassen und andere Probleme verursachen.

James Sneeringer
quelle
1
Das ist einfach verrückt genug, um zu arbeiten
Andrew Lambert
Ich mag es, den Umschlag zu schieben.
James Sneeringer
3

Es gibt kein Werkzeug, das genau aus dem von Ihnen angegebenen Grund so funktioniert. Nur wenige Menschen sind bereit, ein Tool zu schreiben, das bewusst riskantes Verhalten implementiert.

Ignacio Vazquez-Abrams
quelle
Ich hatte gehofft, dass es eine unsichere, nicht standardmäßige Option für ein Dienstprogramm sein würde. Können Sie sich eine Alternative vorstellen? Gibt es eine Möglichkeit, eine vorhandene Datei zu kürzen, um z. B. die ersten 2 GB zu entfernen? Dadurch konnte ich meinen begrenzten freien Speicherplatz verwenden, um einen Block nach dem anderen zu komprimieren und die Quelldatei nach und nach zu verkleinern.
Lee
Es gibt wirklich keine vernünftige Möglichkeit, mit einem beliebigen Tool Daten vom Anfang einer Datei in einem beliebigen Dateisystem zu entfernen.
Ignacio Vazquez-Abrams
2
Sie können jedoch Daten vom Ende der Datei entfernen . Dies kann grundsätzlich erfolgen. Sie schneiden Daten vom Ende der Datei ab, um separate Dateien zu erstellen, und kürzen dabei die Originaldateien. Anschließend komprimieren Sie die Dateien in der Vorwärtsreihenfolge und löschen sie bei Bedarf. Es wäre mühsam zu implementieren und wenn etwas schief gehen würde, würden Sie geschraubt werden. Aber es ist möglich.
David Schwartz
1

Die Befehle split und csplit können verwendet werden, um die große Datei in kleinere Teile aufzuteilen und diese dann einzeln zu komprimieren. Das Zusammenbauen wäre jedoch ziemlich zeitaufwändig.

Brian
quelle
Eine weitere gute Option. Man könnte wahrscheinlich ein Skript schreiben, um dies zu tun. Dies führt jedoch zu vielen separat komprimierten Dateien, die nach dem Dekomprimieren erneut verkettet werden müssen, was nicht so schön ist.
sleske