rust - What is the correct way to write `Vec<u16>` content to a file? -
i'm having trouble writing vec<u16>
content file:
use std::fs::file; use std::io::{write, bufwriter}; use std::mem; #[derive(debug, copy, clone, partialeq)] pub enum imageformat { grayscale, rgb32, } #[derive(debug, copy, clone, partialeq)] pub struct imageheader { pub width: usize, pub height: usize, pub format: imageformat, } pub struct image { pub header: imageheader, pub data: vec<u16>, } fn write_to_file(path: &str, img: &image) -> std::io::result<()> { let f = try!(file::create(path)); let mut bw = bufwriter::new(f); let slice = &img.data[..]; println!("before length: {}", slice.len()); let sl: &[u8]; unsafe { sl = mem::transmute::<&[u16], &[u8]>(slice); } println!("after length: {}", sl.len()); try!(bw.write_all(sl)); return ok(()); } fn main() {}
since write_all()
asks &[u8]
, i'm doing unsafe conversion of &[u16]
&[u8]
. because conversion not change slice length (slice.len()
, sl.len()
have same values), half of image data output file.
it better if don't need unsafe conversion or copying.
to directly you'd want use std::slice::from_raw_parts()
:
use std::slice; use std::mem; fn main() { let slice_u16: &[u16] = &*vec![1, 2, 3, 4, 5, 6]; println!("u16s: {:?}", slice_u16); let slice_u8: &[u8] = unsafe { slice::from_raw_parts( slice_u16.as_ptr() *const u8, slice_u16.len() * mem::size_of::<u16>(), ) }; println!("u8s: {:?}", slice_u8); }
it require unsafe
because from_raw_parts()
can't guarantee can pass valid pointer it, , can create slices arbitrary lifetime.
however, approach not potentially unsafe, not portable. when work integers larger 1 byte, endianness issues arise. if write file in way on x86 machine, read garbage on arm machine. proper way use libraries byteorder
allow specify endianness explicitly:
extern crate byteorder; use byteorder::{writebytesext, littleendian}; fn main() { let slice_u16: &[u16] = &*vec![1, 2, 3, 4, 5, 6]; println!("u16s: {:?}", slice_u16); let mut result: vec<u8> = vec::new(); &n in slice_u16 { let _ = result.write_u16::<littleendian>(n); } println!("u8s: {:?}", result); }
note i've used vec<u8>
here, implements write
, , write_u16()
, other methods writebytesext
trait defined on write
, use these methods directly on bufwriter
, example.
while may less efficient reinterpreting piece of memory, safe , portable.
Comments
Post a Comment