Rust二进制数据序列化库binout的使用,高效处理结构化数据的读写与存储

以下是关于Rust二进制数据序列化库binout的使用介绍和完整示例:

binout是Piotr Beling开发的Rust库,用于低级别、可移植、面向字节的二进制编码、解码、序列化和反序列化整数和整数数组。它支持改进的VByte/LEB128格式以及简单的小端序原生序列化。

示例代码:

use binout::{VByte, Serializer};

let value = 123456u64;
let mut buff = Vec::new();
assert!(VByte::write(&mut buff, value).is_ok());
assert_eq!(buff.len(), VByte::size(value));
let read: u64 = VByte::read(&mut &buff[..]).unwrap();
assert_eq!(read, value);

完整示例demo:

use binout::{VByte, AsIs, Serializer};

fn main() {
    // VByte示例
    let vbyte_value = 123456u64;
    let mut vbyte_buffer = Vec::new();
    
    // 序列化
    VByte::write(&mut vbyte_buffer, vbyte_value).unwrap();
    println!("VByte encoded size: {}", vbyte_buffer.len());
    
    // 反序列化
    let vbyte_decoded: u64 = VByte::read(&mut &vbyte_buffer[..]).unwrap();
    println!("VByte decoded value: {}", vbyte_decoded);

    // AsIs示例
    let asis_value = 123456u64;
    let mut asis_buffer = Vec::new();
    
    // 序列化
    AsIs::write(&mut asis_buffer, asis_value).unwrap();
    println!("AsIs encoded size: {}", asis_buffer.len());
    
    // 反序列化
    let asis_decoded: u64 = AsIs::read(&mut &asis_buffer[..]).unwrap();
    println!("AsIs decoded value: {}", asis_decoded);
}

这个库提供了两种主要的序列化方式:

  1. VByte - 使用改进的VByte/LEB128格式进行压缩编码
  2. AsIs - 使用简单的小端序原生格式

要使用这个库,可以在Cargo.toml中添加依赖:

binout = "0.3.0"

或者运行命令:

cargo add binout

完整示例demo(带注释):

use binout::{VByte, AsIs, Serializer};

fn main() {
    // 初始化测试数据
    let test_value = 123456u64;
    
    // ===== VByte压缩编码示例 =====
    println!("\n=== VByte编码测试 ===");
    
    // 创建缓冲区
    let mut vbyte_buffer = Vec::new();
    
    // 序列化(编码)
    VByte::write(&mut vbyte_buffer, test_value).unwrap();
    println!("编码后大小: {}字节", vbyte_buffer.len());
    
    // 反序列化(解码)
    let decoded: u64 = VByte::read(&mut &vbyte_buffer[..]).unwrap();
    println!("解码值: {}", decoded);
    
    // ===== AsIs原生编码示例 =====
    println!("\n=== AsIs编码测试 ===");
    
    // 创建缓冲区
    let mut asis_buffer = Vec::new();
    
    // 序列化(原生小端序编码)
    AsIs::write(&mut asis_buffer, test_value).unwrap();
    println!("编码后大小: {}字节 (固定8字节)", asis_buffer.len());
    
    // 反序列化
    let decoded: u64 = AsIs::read(&mut &asis_buffer[..]).unwrap();
    println!("解码值: {}", decoded);
    
    // 比较两种编码方式的大小
    println!("\n大小比较: VByte {}字节 vs AsIs {}字节", 
        vbyte_buffer.len(), 
        asis_buffer.len());
}

1 回复

Rust二进制数据序列化库binout的使用指南

介绍

binout是一个Rust语言的高性能二进制数据序列化库,专注于高效处理结构化数据的读写与存储。它具有以下特点:

  • 极简API设计,易于使用
  • 高性能二进制序列化
  • 支持基本数据类型和自定义结构体
  • 内存高效,适合处理大量数据
  • 支持文件读写操作

安装

在Cargo.toml中添加依赖:

[dependencies]
binout = "0.3"

基本使用方法

1. 写入数据

use binout::{Writer, AsIs};

let mut writer = Writer::new_file("data.bin")?;

// 写入基本类型
writer.write(&42u32, AsIs)?;       // 写入u32
writer.write(&3.14f64, AsIs)?;     // 写入f64
writer.write(&true, AsIs)?;         // 写入bool
writer.write(&"hello", AsIs)?;      // 写入字符串

// 写入数组
let arr = [1u8, 2, 3, 4, 5];
writer.write(&arr, AsIs)?;

2. 读取数据

use binout::{Reader, AsIs};

let mut reader = Reader::from_file("data.bin")?;

// 读取基本类型
let num: u32 = reader.read(AsIs)?;
let pi: f64 = reader.read(AsIs)?;
let flag: bool = reader.read(AsIs)?;
let text: String = reader.read(AsIs)?;

// 读取数组
let arr: [u8; 5] = reader.read(AsIs)?;

3. 自定义结构体序列化

use binout::{Serializer, Deserializer, VByte};

#[derive(Debug, PartialEq)]
struct Point {
    x: f32,
    y: f32,
    id: u64,
}

impl Serializer for Point {
    fn serialize(&self, dest: &mut impl std::io::Write) -> std::io::Result<()> {
        self.x.serialize(dest)?;
        self.y.serialize(dest)?;
        self.id.serialize_with(dest, VByte)?;  // 对id使用变长编码
        Ok(())
    }
}

impl Deserializer for Point {
    fn deserialize(src: &mut impl std::io::Read) -> std::io::Result<Self> {
        Ok(Point {
            x: f32::deserialize(src)?,
            y: f32::deserialize(src)?,
            id: u64::deserialize_with(src, VByte)?,
        })
    }
}

// 使用自定义结构体
let point = Point { x: 1.5, y: -2.3, id: 123456789 };

// 写入
let mut writer = Writer::new_file("point.bin")?;
writer.write(&point, AsIs)?;

// 读取
let mut reader = Reader::from_file("point.bin")?;
let loaded_point: Point = reader.read(AsIs)?;

高级特性

1. 使用不同的编码策略

use binout::{VByte, Delta, AsIs};

let data = vec![1000, 1001, 3, 1006, 1010]; // 递增序列

// 写入时使用Delta编码(适合递增序列)
let mut writer = Writer::new_file("delta.bin")?;
writer.write(&data, Delta)?;

// 读取时指定相同的编码
let mut reader = Reader::from_file("delta.bin")?;
let decoded: Vec<u32> = reader.read(Delta)?;

2. 处理大型数据集

use binout::{Writer, Reader, AsIs, VByte};

// 写入大量数据
let mut writer = Writer::new_file("large_data.bin")?;
for i in 0..1_000_000 {
    writer.write(&i, VByte)?;  // 使用变长编码节省空间
}

// 流式读取大数据
let mut reader = Reader::from_file("large_data.bin")?;
while !reader.is_empty() {
    let num: u32 = reader.read(VByte)?;
    // 处理数据...
}

3. 内存映射文件支持

use binout::MappedReader;

// 创建内存映射读取器(适合大文件)
let reader = MappedReader::new("large_data.bin")?;

// 随机访问读取
let num_at_1000: u32 = reader.read_at(1000, VByte)?;

性能提示

  1. 对于小整数,使用VByte编码可以显著减少存储空间
  2. 对于单调递增序列,Delta编码通常是最佳选择
  3. 处理大文件时考虑使用MappedReader进行内存映射
  4. 批量写入数据比单条写入更高效

完整示例DEMO

use binout::{Writer, Reader, AsIs, VByte, Delta, Serializer, Deserializer};
use std::error::Error;

#[derive(Debug, PartialEq)]
struct SensorData {
    timestamp: u64,
    values: Vec<f32>,
    device_id: String,
}

impl Serializer for SensorData {
    fn serialize(&self, dest: &mut impl std::io::Write) -> std::io::Result<()> {
        // 对timestamp使用变长编码
        self.timestamp.serialize_with(dest, VByte)?;
        // 对values使用Delta编码(假设是时间序列数据)
        self.values.serialize_with(dest, Delta)?;
        // 字符串按原样序列化
        self.device_id.serialize(dest)?;
        Ok(())
    }
}

impl Deserializer for SensorData {
    fn deserialize(src: &mut impl std::io::Read) -> std::io::Result<Self> {
        Ok(SensorData {
            timestamp: u64::deserialize_with(src, VByte)?,
            values: Vec::<f32>::deserialize_with(src, Delta)?,
            device_id: String::deserialize(src)?,
        })
    }
}

fn main() -> Result<(), Box<dyn Error>> {
    // 1. 基本类型读写示例
    let mut writer = Writer::new_file("basic.bin")?;
    writer.write(&42u32, AsIs)?;
    writer.write(&3.14f64, AsIs)?;
    writer.write(&"test", AsIs)?;
    
    let mut reader = Reader::from_file("basic.bin")?;
    let num: u32 = reader.read(AsIs)?;
    let pi: f64 = reader.read(AsIs)?;
    let text: String = reader.read(AsIs)?;
    println!("Read basic values: {}, {}, {}", num, pi, text);

    // 2. 自定义结构体示例
    let sensor_data = SensorData {
        timestamp: 1630000000,
        values: vec![25.3, 25.5, 25.7, 26.0, 26.2],
        device_id: "sensor-001".to_string(),
    };

    let mut writer = Writer::new_file("sensor.bin")?;
    writer.write(&sensor_data, AsIs)?;

    let mut reader = Reader::from_file("sensor.bin")?;
    let loaded_data: SensorData = reader.read(AsIs)?;
    println!("Loaded sensor data: {:?}", loaded_data);

    // 3. 大数据集处理示例
    let large_data: Vec<u32> = (0..10000).collect();
    let mut writer = Writer::new_file("large.bin")?;
    writer.write(&large_data, Delta)?;  // 使用Delta编码优化存储

    // 使用内存映射读取大文件
    let reader = MappedReader::new("large.bin")?;
    let value_at_500: u32 = reader.read_at(500, Delta)?;
    println!("Value at index 500: {}", value_at_500);

    Ok(())
}

总结

binout提供了简单而强大的二进制序列化功能,特别适合需要高性能数据存储和读取的Rust应用。通过合理选择编码策略,可以显著优化存储空间和I/O性能。

回到顶部