You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Rust中将已生成的霍夫曼编码写入文件

解决方案

1. 用Serde + Bincode实现紧凑序列化

Bincode是轻量二进制序列化格式,体积紧凑、序列化/反序列化速度快,完全适配你的需求,且能直接和serde配合使用。

步骤:

  • 在Cargo.toml中添加依赖:

    [dependencies]
    bincode = "1.3"
    serde = { version = "1.0", features = ["derive"] }
    bitvec = { version = "1.0", features = ["serde"] }
    
  • 修改代码完成序列化与反序列化:

    use bitvec::prelude::*;
    use std::{collections::HashMap, fs::File, io::{Read, Write}, path::Path};
    use serde::{Deserialize, Serialize};
    
    #[derive(Serialize, Deserialize, Debug)]
    struct HuffmanData {
        dictionary: HashMap<String, char>,
        message: BitVec,
    }
    
    // 省略huffman函数定义(假设功能正常)
    fn huffman(file: File) -> HuffmanData {
        // 你的实现逻辑
        unimplemented!()
    }
    
    fn main() {
        let path = Path::new("data").join("romeo-juliet.txt");
        let file = File::open(path).expect("Could not open file");
        let huffman_data: HuffmanData = huffman(file);
        
        // 保存压缩数据
        let save_path = Path::new("./compressed-data/").join("romeo-juliet.huff");
        let mut save_file = File::create(save_path).unwrap();
        let serialized = bincode::serialize(&huffman_data).unwrap();
        save_file.write_all(&serialized).unwrap();
        
        // 解压示例:读取并反序列化
        let mut read_file = File::open(save_path).unwrap();
        let mut buffer = Vec::new();
        read_file.read_to_end(&mut buffer).unwrap();
        let deserialized: HuffmanData = bincode::deserialize(&buffer).unwrap();
    }
    

    注意:建议给压缩文件使用.huff这类自定义后缀,避免与原文本文件混淆;bitvec已内置serde支持,无需额外处理比特序列的序列化。

2. 手动写入字节(自定义文件格式)

若追求极致紧凑的体积,可自定义文件结构,手动写入字典与压缩数据,完全控制存储细节。

自定义文件结构(按写入顺序):

  • 字典条目数量:用u32存储(4字节)
  • 每个字典条目:
    • 字符的UTF-8字节长度(u8,1字节)
    • 字符的UTF-8字节数据
    • 编码的比特长度(u16,2字节)
    • 编码的字节数据
  • 压缩消息的总比特数(u64,8字节)
  • 压缩消息的字节数据

代码示例(写入部分):

use bitvec::prelude::*;
use std::{collections::HashMap, fs::File, io::Write};

fn save_huffman_manual(dictionary: &HashMap<String, char>, message: &BitVec, file: &mut File) {
    // 写入字典条目数
    let dict_count = dictionary.len() as u32;
    file.write_all(&dict_count.to_le_bytes()).unwrap();
    
    for (code, char) in dictionary {
        // 写入字符的UTF-8数据
        let char_bytes = char.to_string().as_bytes();
        file.write_all(&[char_bytes.len() as u8]).unwrap();
        file.write_all(char_bytes).unwrap();
        
        // 写入编码的比特长度与字节数据
        let code_bitvec = BitVec::<Msb0, u8>::from_iter(code.chars().map(|c| c == '1'));
        file.write_all(&(code_bitvec.len() as u16).to_le_bytes()).unwrap();
        file.write_all(code_bitvec.as_raw_slice()).unwrap();
    }
    
    // 写入压缩消息的总比特数与字节数据
    file.write_all(&(message.len() as u64).to_le_bytes()).unwrap();
    file.write_all(message.as_raw_slice()).unwrap();
}

关键优化点

  • 字典结构:如果你的编码生成逻辑是从字符到编码(HashMap<char, String>),建议序列化这个结构,解压时再转换为反向映射,这样字典的存储更高效,避免重复存储编码字符串。
  • 比特序列存储:利用bitvec的as_raw_slice()直接获取底层字节数组,配合总比特数即可准确还原原始比特序列,避免不必要的比特填充浪费。

内容的提问来源于stack exchange,提问作者Doruk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 01:00:04