2013-05-29 24 views
19

Ho scritto una semplice codifica Huffman in Ruby. Come uscita Ho un array, per esempio:Come faccio a leggere/scrivere file binari?

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

ho bisogno di scrivere, e poi leggere, è da e verso un file. Ho provato diversi metodi:

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

ho un semplice file di testo e non binari.

Oppure:

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

che sembra che funziona, ma poi non riesce a leggere in array.

Quale codifica dovrei usare?

+0

Che cosa vuoi che il tuo file contenga? Personaggi? O bit? O matrice Ruby? O qualcos'altro? –

+0

bit. Coz Ho bisogno di meno dimensioni del file. –

+0

È probabile che la risposta implichi l'uso di 'pack' –

risposta

27

penso che si può semplicemente utilizzare Array#pack e String#unpack come il seguente codice:

# 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" 

Non so il formato preferito per il risultato della lettura e so che il metodo di cui sopra è inefficiente. Ma comunque puoi prendere "0" o "1" sequenzialmente dal risultato di unpack per attraversare il tuo albero Huffman.

+0

@IvanKozlov Qui puoi vedere come leggere i bit nella stringa. Ora hai solo bisogno di dividerlo in pezzi usando la decodifica di Huffman. –

3

Se si desidera utilizzare i bit, è necessario eseguire manualmente il disimballaggio e il disimballaggio. Né Ruby né altri linguaggi di uso comune lo faranno per te.

L'array contiene stringhe costituite da gruppi di caratteri, ma è necessario creare una matrice di byte e scrivere quei byte nel file.

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

si dovrebbe costruire questi byte: 01011111 01011011 10001110 00010011

Dal momento che è solo quattro byte, è possibile metterli in un unico numero a 32 bit che è 010111110101101110001110000100115F5B8E13 esadecimale.

Entrambi i campioni del codice fanno cose diverse. Il primo scrive nel file una rappresentazione in formato stringa di un array Ruby. Il secondo scrive 32 byte dove ognuno è o 48 ('0') o 49 ('1').

Se si desidera utilizzare bit, le dimensioni del file di output devono essere solo quattro byte.

Leggi le operazioni su bit per sapere come ottenerlo.


Ecco una bozza. Non l'ho provato. Qualcosa potrebbe essere sbagliato.

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 

Nota: sette zeri sono aggiunti per gestire caso in cui il numero totale di caratteri non è divisibile per 8. Senza questi zeri, bit_sequence.scan(/.{8}/) cadrà i caratteri rimanenti.

+0

Potresti incollare qualche codice di esempio?Per matrice di maggio, come comprimere e decomprimere? –

+0

In pratica i codici Huffman vengono utilizzati per la compressione o l'archiviazione. Pertanto, mi piacerebbe avere un file con dimensioni minime. Le tue idee a riguardo? Quale metodo suggerisci? –

+0

Ho aggiunto una bozza proprio come un esempio. Non ho avuto il tempo di testarlo attentamente. –

Problemi correlati