我在将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() {}
Run Code Online (Sandbox Code Playgroud)
由于write_all()
一问&[u8]
,我做的一个不安全的转换&[u16]
来&[u8]
.由于转换不会更改切片长度(slice.len()
并且sl.len()
具有相同的值),因此只有一半的图像数据输出到文件.
如果我不需要任何不安全的转换或复制会更好.
要直接执行此操作,您需要使用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);
}
Run Code Online (Sandbox Code Playgroud)
它确实需要,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);
}
Run Code Online (Sandbox Code Playgroud)
请注意,我在Vec<u8>
这里使用过,但是它实现了Write
,并且write_u16()
其他方法WriteBytesExt
都是在trait上定义的Write
,所以你可以直接在a上使用这些方法BufWriter
.
虽然这可能比重新解释一块内存效率稍低,但它是安全且便携的.
我建议使用现有的库进行序列化,例如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()),
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
3374 次 |
最近记录: |