如何从Rust中的二进制文件中读取C结构?

kni*_*t42 5 io serialization rust

我已阅读如何从Rust中的文件读取结构?,但std::slice::raw::mut_buf_as_slice已被弃用,因此我想重新提出这个问题.

我想读一个struct utmp来自/var/run/utmp,我尝试了以下代码:

fn read_utmp() -> Utmp {
    let mut reader = BufReader::new(File::open("/var/run/utmp").unwrap());
    let mut ut = vec![];
    let size = mem::size_of::<Utmp>();
    reader.take(size as u64).read_to_end(&mut ut);
    unsafe {
        std::mem::transmute(ut)
    }
}
Run Code Online (Sandbox Code Playgroud)

正如预期的那样,编译器投诉:

错误:使用不同大小的类型调用transmute:std :: vec :: Vec(192位)到Utmp(3056位)[E0512]

我怎么能这样做?

mal*_*rbo 5

我相信那raw::mut_buf_as_slice被替换为slice::from_raw_parts_mut.


请注意,以下代码未考虑任何字节序填充问题,并且旨在与POD 类型一起使用。struct utmp在这种情况下应该是安全的。


这是一个可以从文件中读取结构体(pod 类型)的函数:

use std::io::{self, BufReader, Read};
use std::fs::{self, File};
use std::path::Path;
use std::slice;

fn read_struct<T, R: Read>(mut read: R) -> io::Result<T> {
    let num_bytes = ::std::mem::size_of::<T>();
    unsafe {
        let mut s = ::std::mem::uninitialized();
        let mut buffer = slice::from_raw_parts_mut(&mut s as *mut T as *mut u8, num_bytes);
        match read.read_exact(buffer) {
            Ok(()) => Ok(s),
            Err(e) => {
                ::std::mem::forget(s);
                Err(e)
            }
        }
    }
}

// use
// read_struct::<Utmp>(reader)
Run Code Online (Sandbox Code Playgroud)

如果要从 utmp 文件中读取所有 utmp 结构,可以执行read_struct多次或一次读取所有文件:

fn read_structs<T, P: AsRef<Path>>(path: P) -> io::Result<Vec<T>> {
    let path = path.as_ref();
    let struct_size = ::std::mem::size_of::<T>();
    let num_bytes = try!(fs::metadata(path)).len() as usize;
    let num_structs = num_bytes / struct_size;
    let mut reader = BufReader::new(try!(File::open(path)));
    let mut r = Vec::<T>::with_capacity(num_structs);
    unsafe {
        let mut buffer = slice::from_raw_parts_mut(r.as_mut_ptr() as *mut u8, num_bytes);
        try!(reader.read_exact(buffer));
        r.set_len(num_structs);
    }
    Ok(r)
}

// use
// read_structs::<Utmp, _>("/var/run/utmp"))
Run Code Online (Sandbox Code Playgroud)