2013-05-29 9 views
19

मैंने रूबी में एक साधारण हफमैन एन्कोडिंग लिखा है। उत्पादन के रूप में मैं एक सरणी मिल गया है, उदाहरण के लिए:मैं बाइनरी फ़ाइलों को कैसे पढ़ूं/लिखूं?

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

मैं लिखने के लिए, और उसके बाद के लिए और एक फ़ाइल से पढ़ने, इसकी आवश्यकता है। मैंने कई विधियों की कोशिश की:

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

मुझे एक साधारण टेक्स्ट फ़ाइल मिलती है और बाइनरी नहीं होती है।

या:

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

कौन सा लगता है कि यह काम करता है, लेकिन फिर मैं यह सरणी में नहीं पढ़ सकते हैं।

मुझे किस एन्कोडिंग का उपयोग करना चाहिए?

+0

आप अपनी फ़ाइल को क्या चाहते हैं? वर्ण? या बिट्स? या रूबी सरणी? या कुछ और? –

+0

बिट्स। Coz मुझे कम फ़ाइल आकार की जरूरत है। –

+0

उत्तर में 'पैक' –

उत्तर

27

मुझे लगता है कि तुम सिर्फ Array#pack और String#unpack उपयोग कर सकते हैं निम्नलिखित कोड की तरह:

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

मुझे पढ़ने का परिणाम के लिए अपना पसंदीदा प्रारूप पता नहीं है और मैं जानता हूँ कि उपरोक्त विधि अक्षम है। लेकिन फिर भी आप अपने हफमैन पेड़ को पार करने के लिए unpack के परिणाम से अनुक्रमिक रूप से "0" या "1" ले सकते हैं।

+0

@IvanKozlov यहां आप देख सकते हैं कि बिट्स को स्ट्रिंग पर वापस कैसे पढ़ा जाए। अब आपको हफमैन डिकोडिंग का उपयोग करके इसे टुकड़ों में विभाजित करने की जरूरत है। –

3

यदि आप बिट्स चाहते हैं, तो आपको मैन्युअल रूप से पैकिंग और अनपॅकिंग दोनों करना होगा। न तो रूबी और न ही कोई अन्य सामान्य उपयोग भाषा आपके लिए यह करेगी।

आपके सरणी में स्ट्रिंग्स हैं जो वर्णों के समूह हैं, लेकिन आपको बाइट्स की सरणी बनाने और फ़ाइल में उन बाइट्स लिखने की आवश्यकता है।

इस से: ["010", "1111", "10", "10", "110", "1110", "001", "110", "000", "10", "011"]

आप इन बाइट्स का निर्माण करना चाहिए: 01011111 01011011 10001110 00010011

चूंकि यह सिर्फ चार बाइट्स है, तो आप उन्हें एक ही 32-बिट संख्या 01011111010110111000111000010011 है कि 5F5B8E13 हेक्स में डाल सकते हैं।

आपके कोड के दोनों नमूने अलग-अलग चीजें करते हैं। पहला फ़ाइल फ़ाइल में रूबी सरणी का स्ट्रिंग प्रस्तुति लिखता है। दूसरा 32 बाइट लिखता है जहां प्रत्येक 48 ('0') या 49 ('1') है।

यदि आप बिट्स चाहते हैं, तो आपका आउटपुट फ़ाइल आकार केवल चार बाइट होना चाहिए।

सीखने के लिए सीखने के लिए थोड़ा संचालन पढ़ें।


यहां एक मसौदा है। मैंने इसका परीक्षण नहीं किया। कुछ गलत हो सकता है।

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 

नोट: सात शून्य मामले को संभालने के लिए जोड़ रहे हैं जब वर्णों की कुल संख्या उन शून्य के बिना 8. से विभाज्य नहीं है, bit_sequence.scan(/.{8}/) शेष वर्ण छोड़ देंगे।

+0

का उपयोग करने का उत्तर शामिल होने की संभावना है क्या आप कुछ नमूना कोड पेस्ट कर सकते हैं?सरणी के लिए, इसे कैसे पैक और अनपैक करना है? –

+0

मूल रूप से हफमैन कोड संपीड़न या संग्रह के लिए उपयोग किया जाता है। तो नतीजतन मैं न्यूनतम आकार के साथ फ़ाइल रखना चाहता हूँ। इसके बारे में आपके विचार? आप किस विधि का सुझाव देते हैं? –

+0

मैंने एक उदाहरण के रूप में एक मसौदा जोड़ा। मेरे पास सावधानीपूर्वक परीक्षण करने का समय नहीं था। –

संबंधित मुद्दे