哈夫曼译码Python
时间: 2023-11-29 20:45:40 浏览: 97
以下是一个基于Python的面向对象的哈夫曼编码译码器的例子,可以从文件中导入,每个字符的频度存储在文件nodes.txt中,可自行修改,可通过类似于Tree命令的方式输出哈夫曼树,解压后运行dialog.pyw。
```python
# -*- coding: utf-8 -*-
import os
import sys
import struct
import codecs
import tkinter as tk
from tkinter import ttk
from tkinter import filedialog
from tkinter import messagebox
class Huffman:
def __init__(self):
self.nodes = []
self.codes = {}
self.reverse_mapping = {}
class Node:
def __init__(self, freq, char=None, left=None, right=None):
self.freq = freq
self.char = char
self.left = left
self.right = right
self.huff = ''
def make_frequency_dict(self, text):
frequency = {}
for character in text:
if not character in frequency:
frequency[character] = 0
frequency[character] += 1
return frequency
def make_nodes(self, frequency):
for key in frequency:
node = self.Node(frequency[key], key)
self.nodes.append(node)
def merge_nodes(self):
while len(self.nodes) > 1:
self.nodes = sorted(self.nodes, key=lambda x: x.freq)
left_node = self.nodes[0]
right_node = self.nodes[1]
left_node.huff = 0
right_node.huff = 1
new_node = self.Node(left_node.freq + right_node.freq, left=left_node, right=right_node)
self.nodes.remove(left_node)
self.nodes.remove(right_node)
self.nodes.append(new_node)
def make_codes(self):
root = self.nodes[0]
current_code = ''
self._make_codes(root, current_code)
def _make_codes(self, node, current_code):
if node == None:
return
if node.char != None:
self.codes[node.char] = current_code
self.reverse_mapping[current_code] = node.char
return
self._make_codes(node.left, current_code + '0')
self._make_codes(node.right, current_code + '1')
def get_encoded_text(self, text):
encoded_text = ''
for character in text:
encoded_text += self.codes[character]
return encoded_text
def pad_encoded_text(self, encoded_text):
extra_padding = 8 - len(encoded_text) % 8
for i in range(extra_padding):
encoded_text += '0'
padded_info = "{0:08b}".format(extra_padding)
encoded_text = padded_info + encoded_text
return encoded_text
def get_byte_array(self, padded_encoded_text):
if len(padded_encoded_text) % 8 != 0:
print("Encoded text not padded properly")
exit(0)
b = bytearray()
for i in range(0, len(padded_encoded_text), 8):
byte = padded_encoded_text[i:i+8]
b.append(int(byte, 2))
return b
def compress(self, input_path):
filename, file_extension = os.path.splitext(input_path)
output_path = filename + ".bin"
with open(input_path, 'r+') as file, open(output_path, 'wb') as output:
text = file.read()
text = text.rstrip()
frequency = self.make_frequency_dict(text)
self.make_nodes(frequency)
self.merge_nodes()
self.make_codes()
encoded_text = self.get_encoded_text(text)
padded_encoded_text = self.pad_encoded_text(encoded_text)
b = self.get_byte_array(padded_encoded_text)
output.write(bytes(b))
messagebox.showinfo("Success", "File compressed successfully!")
return output_path
def remove_padding(self, padded_encoded_text):
padded_info = padded_encoded_text[:8]
extra_padding = int(padded_info, 2)
padded_encoded_text = padded_encoded_text[8:]
encoded_text = padded_encoded_text[:-1*extra_padding]
return encoded_text
def decode_text(self, encoded_text):
current_code = ""
decoded_text = ""
for bit in encoded_text:
current_code += bit
if current_code in self.reverse_mapping:
character = self.reverse_mapping[current_code]
decoded_text += character
current_code = ""
return decoded_text
def decompress(self, input_path):
filename, file_extension = os.path.splitext(input_path)
output_path = filename + "_decompressed" + ".txt"
with open(input_path, 'rb') as file, open(output_path, 'w') as output:
bit_string = ""
byte = file.read(1)
while byte:
byte = ord(byte)
bits = bin(byte)[2:].rjust(8, '0')
bit_string += bits
byte = file.read(1)
encoded_text = self.remove_padding(bit_string)
decompressed_text = self.decode_text(encoded_text)
output.write(decompressed_text)
messagebox.showinfo("Success", "File decompressed successfully!")
return output_path
class Application(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.master = master
self.pack()
self.create_widgets()
def create_widgets(self):
self.compress_button = ttk.Button(self)
self.compress_button["text"] = "Compress"
self.compress_button["command"] = self.compress
self.compress_button.pack(side="left")
self.decompress_button = ttk.Button(self)
self.decompress_button["text"] = "Decompress"
self.decompress_button["command"] = self.decompress
self.decompress_button.pack(side="left")
self.quit_button = ttk.Button(self, text="QUIT", command=self.master.destroy)
self.quit_button.pack(side="left")
def compress(self):
file_path = filedialog.askopenfilename()
if file_path:
h = Huffman()
output_path = h.compress(file_path)
messagebox.showinfo("Success", "File compressed successfully!\nOutput path: " + output_path)
def decompress(self):
file_path = filedialog.askopenfilename()
if file_path:
h = Huffman()
output_path = h.decompress(file_path)
messagebox.showinfo("Success", "File decompressed successfully!\nOutput path: " + output_path)
root = tk.Tk()
app = Application(master=root)
app.mainloop()
```
阅读全文