#binary #io #struct #binary-file

binext

一个用于从/到缓冲区读取/写入结构的库

1个稳定版本

1.0.0 2023年4月11日

#1856编码

每月 23次下载

MIT 许可证

15KB
81

binext

binext是一个库,旨在使处理二进制缓冲区和类似C语言中的结构更加容易。

此库提供了安全接口,可以从/向Read/Write二进制源读取/写入结构。

如果与#[repr(C)]一起使用,这个crate允许在C/C++和Rust之间读取/写入二进制结构。


动机

我发现C/C++允许通过将结构指针转换为char*来从二进制文件中直接写入/读取结构体非常有趣。我想知道Rust是否有任何std实现,或者是否有crate允许我这样做,但我找不到任何。所以我只能自己实现!现在我们就在这里!

示例

纯Rust

从Rust读取/写入文件非常简单,让我们看看一个示例

use binext::{BinaryRead, BinaryWrite};
use std::{io, fs::OpenOptions};

#[derive(Debug)]
struct MyStruct {
    a: usize,
    b: char
}

fn main() -> io::Result<()> {
    // Open a file to write to.
    let mut write_file = OpenOptions::new()
        .create(true)
        .write(true)
        .truncate(true)
        .open("myfile.bin")?;

    let my_struct = MyStruct { a: 128, b: 'a' };
    // Write the struct instance data into the file.
    write_file.write_binary(&my_struct)?;

    drop(write_file);
    drop(my_struct);


    // Now open the same file but in read only mode.
    let mut read_file = OpenOptions::new().read(true).open("myfile.bin")?;

    // This will return a struct with the same data as the instance used to write
    // a: 128, b: 'a'
    let out = read_file.read_binary::<MyStruct>()?;
    println!("{out:?}");

    Ok(())
}

C/C++和Rust

为了能够使用两种语言中编写的数据,Rust结构必须标记为#[repr(C)],同时,类型大小也需要考虑。

例如,在Rust中,char的大小为4字节,在C/C++中为1字节,因此必须考虑到这一点,因为如果结构大小和/或对齐不正确,数据将不会正确。

在这个示例中,我们将使用C++将结构写入文件,然后从Rust中读取它。

C++代码

#include<iostream>
#include<fstream>

using namespace std;

struct SomeData {
    unsigned int a;
    unsigned long long b;
    char msg[13];
};

int main() {
    // Let's assume this operation won't fail.
    ofstream file("myfile.bin");
    
    // Create an instance to write to the file.
    SomeData instance = {
        128,
        256,
        "Hello World!"
    };
    
    // Write the struct to the file.
    file.write((const char*) &instance, sizeof(SomeData));

    return 0;
}

Rust代码

use binext::BinaryRead;
use std::{io, fs::OpenOptions};

#[repr(C)]
#[derive(Debug)]
struct SomeData {
    a: u32,
    b: u64,
    // u8 is the equivalent in rust of C's char
    msg: [u8; 13]
}

fn main() -> io::Result<()> {
    // Open the file in read mode.
    let mut file = OpenOptions::new()
        .read(true)
        .open("myfile.bin")?;

    // Read the structure from the file.
    let data = file.read_binary::<SomeData>()?;

    println!("Data: {data:?}");

    let message = String::from_utf8(data.msg.to_vec()).unwrap();
    println!("{message}");

    Ok(())
}

无运行时依赖项