我无法将Vec<u16>
内容写入文件:
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() {}
由于write_all()
要求&[u8]
,我正在进行&[u16]
到&[u8]
的不安全转换。由于转换不会更改切片长度(slice.len()
和sl.len()
具有相同的值),因此只有一半的图像数据会输出到文件中。
如果我不需要任何不安全的转换或复制,那会更好。
答案 0 :(得分:7)
要直接执行此操作,您需要使用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() as *const u8,
slice_u16.len() * mem::size_of::<u16>(),
)
};
println!("u8s: {:?}", slice_u8);
}
确实需要unsafe
因为from_raw_parts()
不能保证你只能传递一个有效的指针,它也可以创建任意生命周期的切片。
然而,这种方法不仅可能不安全,而且也不便携。使用大于一个字节的整数时,会立即出现字节序问题。如果您在x86计算机上以这种方式编写文件,则会在ARM计算机上读取垃圾。正确的方法是使用像byteorder
这样的库,它们允许您明确指定字节顺序:
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();
for &n in slice_u16 {
let _ = result.write_u16::<LittleEndian>(n);
}
println!("u8s: {:?}", result);
}
请注意,我在这里使用了Vec<u8>
,但它实现了Write
,write_u16()
和WriteBytesExt
特征中的其他方法在任何Write
上定义,所以你可以直接在BufWriter
上使用这些方法,例如。
虽然这可能比重新解释一块内存效率稍低,但它是安全且便携的。
答案 1 :(得分:5)
我建议使用现有的库进行序列化,例如serde和bincode:
extern crate bincode;
extern crate serde;
#[macro_use]
extern crate serde_derive;
use std::error::Error;
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq)]
pub enum ImageFormat {
GrayScale,
Rgb32,
}
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq)]
pub struct ImageHeader {
pub width: usize,
pub height: usize,
pub format: ImageFormat,
}
#[derive(Serialize, Deserialize)]
pub struct Image {
pub header: ImageHeader,
pub data: Vec<u16>,
}
impl Image {
fn save_to_disk(&self, path: &str) -> Result<(), Box<Error>> {
use std::fs::File;
use std::io::Write;
let bytes: Vec<u8> = try!(bincode::serialize(self, bincode::Infinite));
let mut file = try!(File::create(path));
file.write_all(&bytes).map_err(|e| e.into())
}
}
fn main() {
let image = Image {
header: ImageHeader {
width: 2,
height: 2,
format: ImageFormat::GrayScale,
},
data: vec![0, 0, 0, 0],
};
match image.save_to_disk("image") {
Ok(_) => println!("Saved image to disk"),
Err(e) => println!("Something went wrong: {:?}", e.description()),
}
}