FlateCompressor 代码大纲介绍


一、整体概述
  1. 核心功能

    • 基于 zlib 库实现 DEFLATE 算法的压缩/解压缩

    • 支持压缩级别调节(0-9 级)

    • 提供二进制数据的无损压缩与解压

  2. 设计特点

    • PImpl 模式​:隐藏 zlib 实现细节,降低耦合

    • 资源安全​:使用 unique_ptr自动管理内存

    • 禁止拷贝​:防止重复释放资源(删除拷贝构造/赋值)

    • RAII 机制​:构造函数初始化资源,析构函数自动清理


二、类结构解析
class FlateCompressor {
public:
    // 构造/析构
    FlateCompressor();
    ~FlateCompressor(); 

    // 禁用拷贝
    FlateCompressor(const FlateCompressor&) = delete;
    FlateCompressor& operator=(const FlateCompressor&) = delete;

    // 核心接口
    std::vector<uint8_t> Compress(...);  // 压缩
    std::vector<uint8_t> Decompress(...); // 解压
};

三、关键实现细节
  1. PImpl 结构体(Impl)​

    struct Impl {
        z_stream zs;          // zlib 流控制结构
        bool initialized;     // 初始化标志位
        // 构造/析构中管理 zlib 资源
    };
    
    • 封装 zlib 状态,避免头文件暴露 zlib 依赖

    • 析构时自动调用 deflateEnd()防止内存泄漏

  2. 压缩流程(Compress)​

    graph TD
    A[检查输入数据] --> B{已初始化?}
    B -->|否| C[deflateInit]
    B -->|是| D[deflateReset]
    E[预分配输出缓冲区] --> F[deflateBound估算大小]
    G[执行压缩] --> H{是否Z_STREAM_END?}
    H -->|成功| I[截断有效数据]
    H -->|失败| J[返回空向量]
    
  3. 解压流程(Decompress)​

    graph TD
    A[初始化z_stream] --> B[循环解压]
    B --> C[4KB临时缓冲区]
    D[逐块inflate] --> E{检查Z_OK/Z_STREAM_END}
    E -->|失败| F[立即终止]
    G[拼接输出数据] --> H[返回完整解压数据]
    

四、技术亮点
  1. 动态缓冲区管理

    • 压缩:使用 deflateBound()精准预分配最大输出空间

    • 解压:采用流式处理(4KB 分块),避免内存浪费

  2. 状态复用优化

    • 通过 deflateReset()重用已初始化的 z_stream

    • 减少重复初始化开销(适合多次压缩场景)

  3. 健壮性设计

    • 空输入检查:直接返回空向量

    • 错误码处理:压缩失败返回空结果

    • 内存清零:memset(&zs, 0, ...)防止野指针


五、使用示例
// 压缩示例
FlateCompressor compressor;
auto compressed = compressor.Compress(raw_data, 9); 

// 解压示例
auto original_data = compressor.Decompress(compressed);

六、潜在改进方向
  1. 异常处理

    • 当前返回空向量可改为抛出异常携带错误码
  2. 流式支持

    • 添加 CompressChunk()支持分块压缩
  3. 自定义分配器

    • 允许传入自定义内存分配回调函数
  4. 多线程安全

    • 增加锁机制支持并发调用

七、依赖说明
  • 核心库​:zlib (通过 fx_zlib.h封装)

  • 关键头文件​:

    #include "fxcodec/fx_codec_zlib_wrap.h"
    #include "../fx_zlib/include/fx_zlib.h"
    

该实现平衡了性能与易用性,适用于 PDF 处理等需要 Flate 编解码的场景。

头文件

#pragma once

#include <vector>
#include <cstdint>
#include <memory>

class FlateCompressor {
public:
    FlateCompressor();
    ~FlateCompressor();

    // 禁用拷贝(防止资源重复释放)
    FlateCompressor(const FlateCompressor&) = delete;
    FlateCompressor& operator=(const FlateCompressor&) = delete;

    // 压缩数据(返回压缩后的二进制数据)
    std::vector<uint8_t> Compress(const std::vector<uint8_t>& input_data, int compression_level = 6);//压缩范围 0 到9

    // 解压数据(返回原始二进制数据)
    std::vector<uint8_t> Decompress(const std::vector<uint8_t>& compressed_data);

private:
    // PImpl 模式:隐藏 zlib 实现细节
    struct Impl;
    std::unique_ptr<Impl> impl_;
};

实现文件

 #include "fxcodec/fx_codec_zlib_wrap.h"
#include "../fx_zlib/include/fx_zlib.h"

#include <cstring> // for memset

// PImpl 结构体,封装 zlib 状态
struct FlateCompressor::Impl {
    z_stream zs;
    bool initialized = false;

    Impl() {
        memset(&zs, 0, sizeof(zs));
    }

    ~Impl() {
        if (initialized) {
            deflateEnd(&zs); // 确保资源释放
        }
    }
};

// 构造函数
FlateCompressor::FlateCompressor() : impl_(std::make_unique<Impl>()) {}

// 析构函数(unique_ptr 自动释放 impl_)
FlateCompressor::~FlateCompressor() = default;

// 压缩数据
std::vector<uint8_t> FlateCompressor::Compress(const std::vector<uint8_t>& input_data, int compression_level) {
    if (input_data.empty()) {
        return {};
    }

    // 初始化 zlib(如果未初始化)
    if (!impl_->initialized) {
        if (deflateInit(&impl_->zs, compression_level) != Z_OK) {
            return {};
        }
        impl_->initialized = true;
    }
    else {
        deflateReset(&impl_->zs); // 重用已有的 z_stream
    }

    // 设置输入数据
    impl_->zs.next_in = const_cast<Bytef*>(input_data.data());
    impl_->zs.avail_in = static_cast<uInt>(input_data.size());

    // 预分配输出缓冲区
    std::vector<uint8_t> output_buffer(deflateBound(&impl_->zs, static_cast<uLong>(input_data.size())));

    // 设置输出缓冲区
    impl_->zs.next_out = output_buffer.data();
    impl_->zs.avail_out = static_cast<uInt>(output_buffer.size());

    // 执行压缩
    int ret = deflate(&impl_->zs, Z_FINISH);
    if (ret != Z_STREAM_END) {
        return {}; // 压缩失败
    }

    // 调整缓冲区大小以匹配实际压缩数据
    output_buffer.resize(impl_->zs.total_out);

    return output_buffer;
}

// 解压数据
std::vector<uint8_t> FlateCompressor::Decompress(const std::vector<uint8_t>& compressed_data) {
    if (compressed_data.empty()) {
        return {};
    }

    z_stream zs;
    memset(&zs, 0, sizeof(zs));

    if (inflateInit(&zs) != Z_OK) {
        return {};
    }

    zs.next_in = const_cast<Bytef*>(compressed_data.data());
    zs.avail_in = static_cast<uInt>(compressed_data.size());

    // 逐步解压(因为解压后的大小未知)
    std::vector<uint8_t> output_buffer;
    uint8_t temp_buffer[4096]; // 临时缓冲区

    do {
        zs.next_out = temp_buffer;
        zs.avail_out = sizeof(temp_buffer);

        int ret = inflate(&zs, Z_NO_FLUSH);
        if (ret != Z_OK && ret != Z_STREAM_END) {
            inflateEnd(&zs);
            return {};
        }

        // 将解压的数据追加到输出缓冲区
        size_t bytes_decoded = sizeof(temp_buffer) - zs.avail_out;
        output_buffer.insert(output_buffer.end(), temp_buffer, temp_buffer + bytes_decoded);

    } while (zs.avail_out == 0);

    inflateEnd(&zs);
    return output_buffer;
} 

使用代码

#include <iostream>
#include <vector>
#include <string>
#include <chrono>
#include "FlateCompressor.h"  // 包含头文件

// 打印二进制数据的十六进制表示(调试用)
void PrintHex(const std::vector<uint8_t>& data, size_t max_len = 16) {
    std::cout << "Hex Data (" << data.size() << " bytes): ";
    for (size_t i = 0; i < std::min(data.size(), max_len); ++i) {
        printf("%02X ", data[i]);
    }
    if (data.size() > max_len) std::cout << "...";
    std::cout << std::endl;
}

// 生成测试数据(可自定义内容)
std::vector<uint8_t> GenerateTestData(size_t size) {
    std::vector<uint8_t> data(size);
    for (size_t i = 0; i < size; ++i) {
        data[i] = static_cast<uint8_t>(i % 256);  // 循环填充0-255
    }
    return data;
}

// 压缩测试函数
void TestCompression(const std::vector<uint8_t>& original_data, int level) {
    FlateCompressor compressor;

    auto start = std::chrono::high_resolution_clock::now();
    std::vector<uint8_t> compressed = compressor.Compress(original_data, level);
    auto end = std::chrono::high_resolution_clock::now();

    if (compressed.empty()) {
        std::cerr << "Compression failed!" << std::endl;
        return;
    }

    auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
    double ratio = original_data.empty() ? 0 : 
                  (1.0 - (double)compressed.size() / original_data.size()) * 100;

    std::cout << "\n=== Compression Test (Level " << level << ") ===" << std::endl;
    std::cout << "Original Size: " << original_data.size() << " bytes" << std::endl;
    std::cout << "Compressed Size: " << compressed.size() << " bytes" << std::endl;
    std::cout << "Compression Ratio: " << ratio << "%" << std::endl;
    std::cout << "Time: " << duration.count() << " μs" << std::endl;
    PrintHex(compressed);
}

// 解压测试函数
void TestDecompression(const std::vector<uint8_t>& compressed_data) {
    FlateCompressor compressor;

    auto start = std::chrono::high_resolution_clock::now();
    std::vector<uint8_t> decompressed = compressor.Decompress(compressed_data);
    auto end = std::chrono::high_resolution_clock::now();

    if (decompressed.empty()) {
        std::cerr << "Decompression failed!" << std::endl;
        return;
    }

    auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);

    std::cout << "\n=== Decompression Test ===" << std::endl;
    std::cout << "Compressed Size: " << compressed_data.size() << " bytes" << std::endl;
    std::cout << "Decompressed Size: " << decompressed.size() << " bytes" << std::endl;
    std::cout << "Time: " << duration.count() << " μs" << std::endl;
    PrintHex(decompressed);
}

// 完整流程测试(压缩+解压)
void TestRoundTrip() {
    // 生成测试数据(1MB随机数据)
    const size_t test_size = 1024 * 1024;
    std::vector<uint8_t> original_data = GenerateTestData(test_size);

    std::cout << "=== Round Trip Test ===" << std::endl;
    PrintHex(original_data);

    // 测试不同压缩级别
    for (int level = 0; level <= 9; ++level) {
        FlateCompressor compressor;

        // 压缩
        std::vector<uint8_t> compressed = compressor.Compress(original_data, level);
        if (compressed.empty()) {
            std::cerr << "Level " << level << " compression failed!" << std::endl;
            continue;
        }

        // 解压
        std::vector<uint8_t> decompressed = compressor.Decompress(compressed);
        if (decompressed.empty()) {
            std::cerr << "Level " << level << " decompression failed!" << std::endl;
            continue;
        }

        // 验证数据一致性
        if (original_data != decompressed) {
            std::cerr << "Level " << level << " data mismatch!" << std::endl;
        } else {
            double ratio = (1.0 - (double)compressed.size() / original_data.size()) * 100;
            std::cout << "Level " << level << " OK. Ratio: " << ratio << "%" << std::endl;
        }
    }
}

int main() {
    // 示例1:基础压缩/解压
    std::string sample_text = "Hello, FlateCompressor! This is a test string for compression.";
    std::vector<uint8_t> text_data(sample_text.begin(), sample_text.end());

    std::cout << "=== Basic Text Test ===" << std::endl;
    PrintHex(text_data);

    TestCompression(text_data, 6);  // 默认压缩级别
    std::vector<uint8_t> compressed_text = FlateCompressor().Compress(text_data, 6);
    TestDecompression(compressed_text);

    // 示例2:大文件测试
    std::vector<uint8_t> large_data = GenerateTestData(5 * 1024 * 1024); // 5MB数据
    TestCompression(large_data, 9);  // 最高压缩级别

    // 示例3:往返测试
    TestRoundTrip();

    return 0;
}
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐