我应该如何阅读关于字节序的文件内容?

时间:2014-10-09 20:34:04

标签: io coding-style rust endianness idiomatic

好的愚蠢的noob问题,但我显然在文档中遗漏了一些东西。

我可以看到在Rust中我可以使用以下命令将文件读取到字节数组:

File::open(&Path::new("fid")).read_to_end();

我还可以用大端或小端格式读取一个u32:

File::open(&Path::new("fid")).read_be_u32();
File::open(&Path::new("fid")).read_le_u32();

但据我所知,我将不得不做这样的事情(简化):

let path = Path::new("fid");                         
let mut file = File::open(&path);                                                         
let mut v = vec![];                                  
for n in range(1u64, path.stat().unwrap().size/4u64){
    v.push(if big {                                  
        file.read_be_u32()                           
    } else {                                         
        file.read_le_u32()                           
    });                                              
}

但这很难看,我只是想知道是否有更好的方法来做到这一点。

好的,所以循环中的if是丑陋的一小部分,所以我按照建议提升,新版本如下:

let path = Path::new("fid");
let mut file = File::open(&path);
let mut v = vec![];
let fun = if big {
    ||->IoResult<u32>{file.read_be_u32()}
} else {
    ||->IoResult<u32>{file.read_le_u32()}
};
for n in range(1u64, path.stat().unwrap().size/4u64){
    v.push(fun());
}

了解range_step并使用_作为索引,所以现在我离开了:

let path = Path::new("fid");
let mut file = File::open(&path);
let mut v = vec![];
let fun = if big {
    ||->IoResult<u32>{file.read_be_u32()}
} else {
    ||->IoResult<u32>{file.read_le_u32()}
};
for _ in range_step(0u64, path.stat().unwrap().size,4u64){
    v.push(fun().unwrap());
}

还有什么建议吗?这已经看起来好多了。

1 个答案:

答案 0 :(得分:1)

此解决方案将整个文件读入缓冲区,然后创建缓冲区视图作为单词,然后将这些单词映射到向量中,转换字节顺序。 collect()避免了生成可变载体的所有重新分配。您也可以mmap该文件,而不是将其读入缓冲区。

use std::io::File;
use std::num::{Int, Num};

fn from_bytes<'a, T: Num>(buf: &'a [u8]) -> &'a [T] {
    unsafe {
        std::mem::transmute(std::raw::Slice {
            data: buf.as_ptr(),
            len: buf.len() / std::mem::size_of::<T>()
        })
    }
}

fn main() {
    let buf = File::open(&Path::new("fid")).read_to_end().unwrap();
    let words: &[u32] = from_bytes(buf.as_slice());
    let big = true;
    let v: Vec<u32> = words.iter().map(if big {
        |&n| { Int::from_be(n) }
    } else {
        |&n| { Int::from_le(n) }
    }).collect();
    println!("{}", v);
}