I have read How to read a struct from file in Rust?, but std::slice::raw::mut_buf_as_slice
has been deprecated, hence I want to re-ask this question.
I want to read a struct utmp
from /var/run/utmp
, and I have tried the following code:
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)
}
}
And as expected, the compiler complaint:
error: transmute called with differently sized types: std::vec::Vec (192 bits) to Utmp (3056 bits) [E0512]
How could I do this?
Beware this is not a foolproof process, as if the file is changed, you can could get a SIGBUS error. Reading a binary file is not really different from an ASCII file. But you should be aware of any endianess issues, and use the byteorder crate, although not really related to the Rust read methods per se.
Basically, there're 3 ways of reading ASCII files in Rust, and an additional possibly more harmful. 1.loading the entire file in a String. This is done using the std::fs::read_to_string () method. If you're familiar with Python or Ruby, this method is as convenient as Python's read () function or Ruby's File.read () methods.
Prerequisite: Structure in C For writing in file, it is easy to write string or int to file using fprintf and putc, but you might have faced difficulty when writing contents of struct. fwrite and fread make task easier when you want to write and read blocks of data. fwrite : Following is the declaration of fwrite function
This article will demonstrate multiple methods of how to read a binary file in C. fread is part of the C standard library input/output facilities, and it can be utilized to read binary data from regular files. The C standard library implements a user-buffered I/O along with a platform-independent solution to handle reading/writing binary file data.
I believe that raw::mut_buf_as_slice
was replaced with slice::from_raw_parts_mut
.
Note that the following code does not take into account any endianness or padding issues and is intended to be used with POD types. struct utmp
should be safe in this case.
Here is a function that can read a struct (of a pod type) from a file:
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)
If you want to read all utmp structs from the utmp file, you can execute read_struct
multiple times or read all the file at once:
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"))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With