2013-05-29 11 views
19

Napisałem proste kodowanie Huffmana w Ruby. Jako wyjście Mam tablicę, na przykład:Jak mogę odczytać/zapisać pliki binarne?

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

muszę napisać, a potem czytać ją do iz pliku. Próbowałem kilka metod:

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

Otrzymuję prosty plik tekstowy, a nie binarny.

Lub:

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

który wygląda jak to działa, ale potem nie może odczytać go do tablicy.

Z jakiego kodowania należy korzystać?

+0

Co chcesz, aby plik zawierał? Postacie? Lub bity? Lub tablica Ruby? Albo coś innego? –

+0

Bity. Bo potrzebuję mniejszy rozmiar pliku. –

+0

Odpowiedź będzie prawdopodobnie wymagać użycia 'paczkę' –

Odpowiedz

27

myślę, że można po prostu użyć Array#pack i String#unpack jak następujący kod:

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

nie wiem preferowany format wyniku czytania i wiem, że powyższa metoda jest nieefektywne. Ale mimo to możesz wziąć "0" lub "1" sekwencyjnie od wyniku unpack, aby przemierzać swoje drzewo Huffmana.

+0

@IvanKozlov Tutaj możesz zobaczyć, jak odczytywać bity z powrotem do napisu. Teraz wystarczy podzielić go na kawałki za pomocą dekodowania Huffmana. –

3

Jeśli chcesz bity, musisz ręcznie za każdym razem rozpakować i rozpakować. Ani Ruby, ani żaden inny typowy język nie zrobi tego za Ciebie.

Twoja tablica zawiera ciągi znaków, które są grupami znaków, ale musisz zbudować tablicę bajtów i wpisać te bajty do pliku.

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

należy budować te bajtów: 01011111 01011011 10001110 00010011

Ponieważ jest to zaledwie cztery bajty, można umieścić je w jednym szeregu 32-bitowym 01011111010110111000111000010011 że jest 5F5B8E13 hex.

Obie próbki kodu wykonują różne czynności. Pierwszy zapisuje do pliku ciąg znaków reprezentujący tablicę Ruby. Drugi zapisuje 32 bajty, gdzie każdy jest albo 48 ("0") lub 49 ("1").

Jeśli chcesz bity, to rozmiar pliku wyjściowego powinien wynosić tylko cztery bajty.

Przeczytaj o operacjach bitowych, aby dowiedzieć się, jak to osiągnąć.


Oto szkic. Nie przetestowałem tego. Coś może być nie tak.

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 

Uwaga: siedem zer dodaje obsłużyć przypadek, gdy łączna liczba znaków nie jest podzielna przez 8. Bez tych zer, bit_sequence.scan(/.{8}/) spadnie pozostałe znaki.

+0

. Czy możesz wkleić przykładowy kod?Aby uzyskać tablicę, jak ją spakować i rozpakować? –

+0

Zasadniczo kody Huffmana służą do kompresji lub archiwizacji. Dlatego chciałbym mieć plik o minimalnym rozmiarze. Twoje pomysły na ten temat? Którą metodę sugerujesz? –

+0

Dodałem szkic jako przykład. Nie miałem czasu, żeby to przetestować. –

Powiązane problemy