2010-03-09 3 views
32

Ich habe viele PDF-Dateien im Speicher erstellt und möchte sie in eine Zip-Datei komprimieren, bevor ich sie als E-Mail-Anhang sende. Ich habe mir Rubyzip angeschaut und es erlaubt mir nicht, eine Zip-Datei zu erstellen, ohne sie auf der Festplatte zu speichern (vielleicht liege ich falsch).Wie kann ich Zip-Datei erzeugen, ohne mit Ruby auf der Festplatte zu speichern?

Gibt es eine Möglichkeit, diese Datei zu komprimieren, ohne eine temporäre Datei zu erstellen?

+0

Siehe [die Antwort von @vas] (http://stackoverflow.com/a/9712252/244128), es macht genau das, was Sie wollen! – maerics

Antwort

38

Ich hatte ein ähnliches Problem, das ich mit dem Rubyzip-Juwel und dem Stringio-Objekt gelöst habe. Es stellt sich heraus, dass rubyzip eine Methode bereitstellt, die ein Stringio-Objekt zurückgibt: ZipOutputStream.write_buffer.

Sie können die Zip-Dateistruktur nach Belieben mit put_next_entry erstellen und schreiben. Sobald Sie fertig sind, können Sie die Zeichenfolge zurückspulen und die Binärdaten mit sysread lesen.

Siehe das folgende einfache Beispiel (funktioniert für Rubyzip 0.9.X)

require 'zip/zip' 
stringio = Zip::OutputStream.write_buffer do |zio| 
    zio.put_next_entry("test.txt") 
    zio.write "Hello world!" 
end 
stringio.rewind 
binary_data = stringio.sysread 

Getestet auf jruby 1.6.5.1 (Rubin-1.9.2-p136) (2011-12-27 1bf37c2) (Java HotSpot (TM) 64-Bit Server VM 1.6.0_29) [Windows Server 2008-amd64-java])

Das folgende Beispiel funktioniert für rubyzip> = 1.0.0

require 'rubygems'  
require 'zip' 
stringio = Zip::OutputStream.write_buffer do |zio| 
    zio.put_next_entry("test.txt") 
    zio.write "Hello world!" 
end 
binary_data = stringio.string 

getestet auf jruby 1.7.22 (1.9.3p551) 2015.08.20 c28f492 auf OpenJDK 64- Bit Server VM 1.7.0_79-b14 + jit [linux-amd64] und rubyzip gem 1.1.7

+0

Danke, es funktioniert. Zu der Zeit, als ich die Frage schrieb, existierte die Methode noch nicht. Es wurde am 2011-01-07 hinzugefügt. Danke für Ihre Antwort und das nächste Mal, dass ich im Speicher zippen muss, werde ich wissen, wie. – Martinos

+1

LoadError kann solche Datei nicht laden - zip –

+1

Oben funktioniert mit älteren Versionen von Rubyzip gem. Version 1.0 hat die Schnittstelle geändert. Siehe auch: https://github.com/rubyzip/rubyzip#important-note – vas

1

Es gibt zwei RubyZip-Bibliotheken, die ich finden konnte.

  1. Chilkat's Ruby Zip Library
  2. rubyzip on Sourceforge

definitiv Chilkat Bibliothek erlaubt es, eine Zip-Datei im Speicher zu erstellen, anstatt sie auf die Festplatte automatisch zu schreiben, wie in diesen Links gesehen: Zip to Memory, Zip from in memory data

Die eine auf SourceForge, auf der anderen Seite, bietet möglicherweise eine Option zum Zippen einer Datei im Speicher, aber ich bin nicht ganz sicher, da ich Ruby neu bin. Das SourceForge-Rubyzip basiert auf java.util.zip, was dazu geführt hat, dass es eine Klasse namens ZipOutputStream hat. Ich weiß nicht, wie gut die rubyzip Implementierung ist, aber mit java.util.zip Implementierung kann die OutputStream auf ByteArrayOutputStream eingestellt werden, FileOutputStream, FilterOutputStream, ObjectOutputStream, OutputStream, PipedOutputStream ....

Wenn das für die rubyzip Umsetzung gilt dann Es sollte eine Frage der Verwendung von ZipOutputStream sein, um eine ByteArrayOutputStream Art zu übergeben, die dazu führen würde, dass es in den Speicher ausgegeben wird.

Wenn es nicht in Rubyzip existiert, dann bin ich mir sicher, dass Sie immer Ihre eigene Implementierung schreiben und sie für die Aufnahme in Rubyzip einreichen können, da sie opensource ist.

+0

Die eine, die ich bezog, war das Juwel: http://rubygems.org/gems/rubyzip Ich möchte nicht die Chilkat-Bibliothek verwenden, da es nicht Open Source ist. – Martinos

+0

Ich werde das nicht abwerten, aber ich habe nirgendwo einen Kommentar wie "Nein, die Standard-Ruby-ZIP-Klassen können das NICHT" finden. Ich glaube, du hättest damit anfangen sollen. – dimitarvp

+0

Tatsächlich nimmt die neue ZipOutputStream-Methode einen Dateinamen als Argument, ich habe keine Möglichkeit gefunden, ein IO-Objekt zu übergeben. – Martinos

0

Wenn Sie unter Linux arbeiten und je nachdem, wie viel Arbeitsspeicher Sie haben und wie groß Ihre Dateien sind, können Sie immer tmpfs (shared memory) verwenden. Dann funktionieren die rubyzip-basierten Methoden. http://www.mjmwired.net/kernel/Documentation/filesystems/tmpfs.txt

+0

Mounting erfordert Superuser-Berechtigungen –

+0

@AbeVoelker Ja, diese Antwort geht davon aus, dass Sie bereits einen Tmpfs haben oder einen freundlichen lokalen Systemadministrator haben. – g33kz0r

5

Ruby kommt mit einer sehr günstigen StringIO Bibliothek - das kann für die Verwendung einer Zeichenfolge als Ausgabe IO-Objekt oder zum Faken Lesen einer Datei mit einem String unterstützt werden.

Die Herausforderung dabei ist, dass RubyZip nicht direkt unterstützt ein IO-Objekt zu nehmen, wenn ein Zip::ZipOutputStream erstellen, aber wenn man sich der Umsetzung der initialize aussehen, und je nach Bereitschaft zu experimentieren, können Sie in der Lage sein, die Klasse zu erweitern und erlauben Sie es, entweder ein IO-Objekt oder einen Dateinamen im Konstruktor zu nehmen.

Verwandte Themen