2013-05-29 15 views
19

Ich habe eine einfache Huffman-Codierung in Ruby geschrieben. Als Ausgabe habe ich ein Array bekommt, zum Beispiel:Wie lese/schreibe ich binäre Dateien?

["010", "1111", "10", "10", "110", "1110", "001", "110", "000", "10", "011"] 

ich schreiben müssen, und dann zu lesen, um es zu und aus einer Datei. Ich habe versucht, verschiedene Methoden:

IO.binwrite("out.cake", array) 

ich eine einfache Textdatei bekommen und nicht binär.

Oder:

File.open("out.cake", 'wb') do |output| 
    array.each do | byte | 
     output.print byte.chr 
    end 
end 

Welche sieht aus wie es funktioniert, aber dann kann ich es nicht in Array lesen.

Welche Codierung soll ich verwenden?

+0

Was soll Ihre Datei enthalten? Figuren? Oder Bits? Oder Ruby-Array? Oder etwas anderes? –

+0

Bits. Coz ich brauche weniger Dateigröße. –

+0

Die Antwort bezieht sich wahrscheinlich auf 'pack' –

Antwort

27

Ich glaube, Sie nur Array#pack und String#unpack wie der folgenden Code verwenden:

# Writing 
a = ["010", "1111", "10", "10", "110", "1110", "001", "110", "000", "10", "011"] 
File.open("out.cake", 'wb') do |output| 
    output.write [a.join].pack("B*") 
end 

# Reading 
s = File.binread("out.cake") 
bits = s.unpack("B*")[0] # "01011111010110111000111000010011" 

ich nicht Ihr bevorzugtes Format für das Ergebnis des Lesens weiß, und ich weiß, dass das obige Verfahren ineffizient ist. Aber trotzdem können Sie "0" oder "1" sequentiell vom Ergebnis unpack nehmen, um Ihren Huffman-Baum zu durchqueren.

+0

@IvanKozlov Hier können Sie sehen, wie Sie die Bits zurück in die Zeichenfolge lesen. Jetzt müssen Sie es nur noch in Teile unter Verwendung der Huffman-Decodierung aufteilen. –

3

Wenn Sie Bits wollen, dann müssen Sie sowohl manuell packen als auch entpacken. Weder Ruby noch irgendeine andere gebräuchliche Sprache wird es für dich tun.

Ihr Array enthält Zeichenfolgen, die Gruppen von Zeichen sind, aber Sie müssen ein Array von Bytes erstellen und diese Bytes in die Datei schreiben.

Daraus: ["010", "1111", "10", "10", "110", "1110", "001", "110", "000", "10", "011"]

Sie dieses Bytes bauen sollte: 01011111 01011011 10001110 00010011

Da es nur vier Bytes ist, können Sie sie in eine einzige 32-Bit-Zahl 01011111010110111000111000010011 setzen, die 5F5B8E13 hex ist.

Beide Beispiele Ihres Codes machen unterschiedliche Dinge. Der erste schreibt eine String-Repräsentation eines Ruby-Arrays in die Datei. Die zweite schreibt 32 Bytes, wobei jede entweder 48 ('0') oder 49 ('1') ist.

Wenn Sie Bits benötigen, sollte die Ausgabedateigröße nur vier Byte betragen.

Lesen Sie über Bitoperationen, um zu erfahren, wie Sie das erreichen können.


Hier ist ein Entwurf. Ich habe es nicht getestet. Etwas könnte falsch sein.

a = ["010", "1111", "10", "10", "110", "1110", "001", "110", "000", "10", "011"] 

# Join all the characters together. Add 7 zeros to the end. 
bit_sequence = a.join + "0" * 7 # "010111110101101110001110000100110000000" 

# Split into 8-digit chunks. 
chunks = bit_sequence.scan(/.{8}/) # ["01011111", "01011011", "10001110", "00010011"] 

# Convert every chunk into character with the corresponding code. 
bytes = chunks.map { |chunk| chunk.to_i(2).chr } # ["_", "[", "\x8E", "\x13"] 

File.open("my_huffman.bin", 'wb') do |output| 
    bytes.each { |b| output.write b } 
end 

Hinweis: sieben Nullen hinzugefügt Fall zu behandeln, wenn die Gesamtzahl der Zeichen, die von 8. Ohne diese Nullen nicht teilbar ist, bit_sequence.scan(/.{8}/) werden die restlichen Zeichen fallen.

+0

Können Sie etwas Beispielcode einfügen?Für may Array, wie man es packt und entpackt? –

+0

Grundsätzlich werden Huffman-Codes zur Komprimierung oder Archivierung verwendet. Daher möchte ich eine Datei mit minimaler Größe haben. Deine Ideen dazu? Welche Methode schlagen Sie vor? –

+0

Ich habe einen Entwurf nur als Beispiel hinzugefügt. Ich hatte keine Zeit, es sorgfältig zu testen. –

Verwandte Themen