2009-08-24 6 views
3

Ich versuche, vorzeichenlose Integer aus einer Datei (gespeichert als fortlaufendes Byte) zu lesen und sie in Integer umzuwandeln. Ich habe es versucht:Ruby - Bytes aus einer Datei lesen, in Ganzzahl konvertieren

file = File.new(filename,"r") 
num = file.read(2).unpack("S") #read an unsigned short 
puts num #value will be less than expected 

Was mache ich hier falsch?

Antwort

1

Ok, ich habe es zu arbeiten:

num = file.read(8).unpack("N") 

Vielen Dank für all Eure Hilfe.

0

In welchem ​​Format sind die Zahlen in der Datei gespeichert? Ist es in hex? Ihr Code sieht für mich korrekt aus.

+0

Gemäß der VM-Spezifikation: "Multibyte-Datenelemente werden immer in Big-Endian-Reihenfolge gespeichert, wobei die hohen Bytes zuerst kommen." – Peter

1

Wenn Sie mit Binärdaten arbeiten, müssen Sie sicherstellen, dass Sie die Datei im Binärmodus öffnen, wenn Sie Windows verwenden. Dies gilt sowohl für das Lesen als auch für das Schreiben.

open(filename, "rb") do |file| 
    num = file.read(2).unpack("S") 
    puts num 
end 

Je nach Quellplattform können auch Probleme mit der Codierung "endian" auftreten. Zum Beispiel PowerPC-basierte Maschinen, zu denen alte Mac-Systeme, IBM Power Server, PS3-Cluster oder Sun Sparc-Server gehören.

Können Sie ein Beispiel wie es ist "weniger"? Normalerweise gibt es ein offensichtliches Muster für die Daten.

Zum Beispiel, wenn Sie 0x1234 wollen, aber Sie 0x3412 bekommen, ist es ein Endian Problem.

+0

Ich versuche, die magische Nummer einer Java-.class-Datei zu lesen. Mein Code produziert 202 als magische Zahl, während es 3405691582 (0xCAFEBABE) sein sollte. Das änderte sich nicht, als ich "rb" benutzte. – Peter

+0

Auch ich bin auf Linux, muss ich mir Sorgen machen, die Datei im Binärmodus immer noch zu öffnen? – Peter

+0

Es ist immer noch gut, den Binärmodus explizit unter Unix zu verwenden. Es tut nicht weh (es ist nur ein No-Op), aber a.) Es macht Ihren Code klarer und b.) Spart Ihnen Tonnen von Debugging, wenn jemand Ihren Code unter Windows läuft. –

6

Sie lesen nicht genug Bytes. Wie Sie im Kommentar zu Tadman Antwort sagen, erhalten Sie 202 statt 3405691582

Beachten Sie, dass die ersten 2 Bytes 0xCAFEBABE ist 0xCA = 202

Wenn Sie wirklich alle 8 Bytes in einer einzigen Zahl möchten, können Sie dann müssen mehr als die unsigned short

versuchen

num = file.read(8).unpack("L_") 

der Unterstrich gelesen wird, unter der Annahme, dass die native lange wird 8 Bytes sein, was definitiv nicht garantiert ist.

+0

Ich habe es versucht, und ich bekomme stattdessen 3199925962 (was immer noch nicht stimmt!). Gibt es auch einen plattformübergreifenden Weg dies zu implementieren? – Peter

+1

erstes Byte ist 0xCA, die ersten beiden sind 0xCAFE – rampion

+2

'3199925962 = 0xBEBAFECA', also sieht es so aus, als ob Sie ein Byte-Ordnungsproblem haben. Für die Kreuzplatformität verlasse ich mich normalerweise auf die Netzwerk-Byte-Reihenfolge und nicht auf die Host-Byte-Reihenfolge. – rampion

2

Es gibt ein paar Bibliotheken, die beim Analysieren von Binärdaten in Ruby helfen, indem Sie das Datenformat in einer einfachen deklarativen DSL deklarieren und dann das Packen, Entpacken, Bit-Twiddling, Verschieben und Endian-Konvertierungen von selbst.

Ich habe nie eine von diesen verwendet, aber hier sind zwei Beispiele. (Es gibt mehr, aber ich kenne sie nicht):

4

Wie wäre es mit einem Blick in die Spitzhacke? (Ruby 1.9, S. 44)

File.open("testfile") 
do |file| 
    file.each_byte {|ch| print "#{ch.chr}:#{ch} " } 
end 

Each_byte iteriert byteweise über eine Datei.