Lesen Sie die Binärdatei als Zeichenfolge in Ruby

263

Ich brauche eine einfache Möglichkeit, eine TAR-Datei in eine Zeichenfolge zu konvertieren (und umgekehrt). Gibt es eine Möglichkeit, dies in Ruby zu tun? Mein bester Versuch war folgender:

file = File.open("path-to-file.tar.gz")
contents = ""
file.each {|line|
  contents << line
}

Ich dachte, das würde ausreichen, um es in einen String umzuwandeln, aber wenn ich dann versuche, es so wieder aufzuschreiben ...

newFile = File.open("test.tar.gz", "w")
newFile.write(contents)

Es ist nicht dieselbe Datei. Wenn Sie dies tun ls -l, werden die Dateien unterschiedlich groß, obwohl sie ziemlich nahe beieinander liegen (und beim Öffnen der Datei werden die meisten Inhalte intakt angezeigt). Gibt es einen kleinen Fehler, den ich mache, oder einen ganz anderen (aber praktikablen) Weg, dies zu erreichen?

Chris Bunch
quelle
3
Das ist eine gezippte TAR-Datei (hoffe ich). Es gibt keine "Linien". Bitte klären Sie, was Sie erreichen wollen.
Brent.Longborough
Versuchen Sie, die komprimierten Daten oder unkomprimierten Inhalte zu betrachten?
David Nehme
Zeichen in einem komprimierten Datenstrom haben also eine Chance von ungefähr 1 zu 256, auf "\ n" zu landen, das das Ende einer Zeile definiert, und das ist in Ordnung, wenn nicht auch "\ r" erwartet wird, siehe meine Antwort unten
Purfideas,
Diese Frage sollte in " Binärdatei in Zeichenfolge konvertieren " umbenannt werden, da IO.readdies sonst die bevorzugte Antwort wäre.
Ian

Antworten:

397

Zunächst sollten Sie die Datei als Binärdatei öffnen. Dann können Sie die gesamte Datei mit einem Befehl einlesen.

file = File.open("path-to-file.tar.gz", "rb")
contents = file.read

Dadurch erhalten Sie die gesamte Datei in einer Zeichenfolge.

Danach möchten Sie wahrscheinlich file.close. Wenn Sie dies nicht tun, filewird es erst geschlossen, wenn es durch Müll gesammelt wurde. Dies wäre eine leichte Verschwendung von Systemressourcen, solange es geöffnet ist.

David Nehme
quelle
22
Das Binärflag ist nur unter Windows relevant und lässt den Dateideskriptor offen. File.read (...) ist besser.
Daniel Huckstep
Stimmt etwas nicht, wenn so viele Leute dies nachschlagen und es als Einzeiler-Lösung kopieren (wie so viele Dinge beim Stackoverflow)? Immerhin funktioniert es, und der Name für diese Funktionen war nur eine willkürliche Wahl der Designer der Ruby-Bibliothek. Wenn wir nur eine Sprache mit Synonymen hätten ... die irgendwie immer noch genau weiß, was wir in Randfällen / mehrdeutigen Fällen wollen. Dann würde ich einfach contents = (contents of file "path to file.txt" as string).
Masterxilo
2
Dies sollte in begin {..open..} ensure {..close..} endBlöcken erfolgen
shadowbq
3
@ArianFaurtosh Nein, es ist eine andere Methode zum Lesen der Datei - es bedeutet nicht, dass sie als ausführbar behandelt und ausgeführt wird! Das wäre ein schrecklicher Nebeneffekt für eine einfache Lesemethode.
Matthew Read
1
@ David, kannst du nicht einfach den folgenden Einzeiler machen? contents = File.binread('path-to-file.tar.gz')Siehe Apidock . Fileist eine Unterklasse von IO.
Vas
244

Wenn Sie den Binärmodus benötigen, müssen Sie dies auf die harte Tour tun:

s = File.open(filename, 'rb') { |f| f.read }

Wenn nicht, ist kürzer und süßer:

s = IO.read(filename)

quelle
In Ruby 1.9.3+ gibt IO.read eine Zeichenfolge an, die mit der Codierung in Encoding.default_external gekennzeichnet ist. Ich denke (?), Dass die Bytes alle so sind, wie sie in der Datei waren, also ist es nicht genau "nicht binärsicher", aber Sie müssen es mit der Binärcodierung versehen, wenn Sie dies möchten.
Jrochkind
Wenn Kürze und Süße von entscheidender Bedeutung sind, gibt der kaufmännische Und-Symbol-Proc-Tricks = File.open(filename, 'rb', &:read)
Epigene
114

Um zu vermeiden, dass die Datei geöffnet bleibt, übergeben Sie am besten einen Block an File.open. Auf diese Weise wird die Datei geschlossen, nachdem der Block ausgeführt wurde.

contents = File.open('path-to-file.tar.gz', 'rb') { |f| f.read }
Aaron Hinni
quelle
10
Dies ist eine bessere Antwort als die von David Nehme, da Dateideskriptoren eine endliche Systemressource sind und deren Erschöpfung ein häufiges Problem ist, das leicht vermieden werden kann.
Jeff McCune
17

auf os x sind diese für mich gleich ... könnte dies vielleicht ein zusätzliches "\ r" in Windows sein?

In jedem Fall können Sie besser sein mit:

contents = File.read("e.tgz")
newFile = File.open("ee.tgz", "w")
newFile.write(contents)
Purfideas
quelle
Dies scheint die einfachste Lösung zu sein.
Dishcandanty
17

Wie wäre es mit etwas Sicherheit beim Öffnen / Schließen?

string = File.open('file.txt', 'rb') { |file| file.read }
Alex
quelle
warum nicht eine explizite .close? Wie in der OP-Datei. Schließen, wenn fertig?
Joshua
2
File.open () {| file | Block} wird automatisch geschlossen, wenn der Block beendet wird. ruby-doc.org/core-1.9.3/File.html#method-c-open
Alex
14
Dies ist identisch mit Aaron Hinnis Antwort , die 2008 veröffentlicht wurde (außer dass die Datei- und Variablennamen von OP nicht verwendet wurden) ...
Abe Voelker
10

Ruby hat binäres Lesen

data = IO.binread(path/filaname)

oder wenn weniger als Ruby 1.9.2

data = IO.read(path/file)
Bardzo
quelle
7

Sie können die TAR-Datei wahrscheinlich in Base64 codieren. Base 64 bietet Ihnen eine reine ASCII-Darstellung der Datei, die Sie in einer Nur-Text-Datei speichern können. Anschließend können Sie die TAR-Datei abrufen, indem Sie den Text zurückdecodieren.

Du machst so etwas wie:

require 'base64'

file_contents = Base64.encode64(tar_file_data)

Schauen Sie sich die Base64 Rubydocs an, um eine bessere Vorstellung zu bekommen.


quelle
Großartig, das sieht so aus, als würde es auch funktionieren! Ich muss es überprüfen, wenn das Lesen des binären Inhalts aus irgendeinem Grund sauer wird.
Chris Bunch
0

Wenn Sie die TAR-Datei mit Base64 codieren (und in einer Nur-Text-Datei speichern) können, können Sie sie verwenden

File.open("my_tar.txt").each {|line| puts line}

oder

File.new("name_file.txt", "r").each {|line| puts line}

um jede (Text-) Zeile im cmd zu drucken.

Boris
quelle