【问题标题】:How should I read the contents of a file respecting endianess?我应该如何阅读有关字节顺序的文件内容?
【发布时间】:2014-12-04 22:01:45
【问题描述】:

我可以看到,在 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());
}

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

【问题讨论】:

  • 这不是丑。如果你想看丑陋的下载 Parrot VM 源代码并看看我必须在 C 中做什么。:) 说真的,如果你不想看它,就把它抽象掉。我透明地检测字节顺序的方法是在文件头存储一个幻数(如 1234),并在运行时使用它来检测字节顺序。至于原语,显然 Rust 已经提供了它们。 (文件::read_be_u32等)
  • 为了提高效率,您可能希望将分支提升出循环 - 可能一直到模板参数。 gold 链接器做到了这一点,它是巨大的
  • @codenheim:U+FEFF 是标准 BOM,在这种情况下对我来说是个不错的选择。
  • @ChrisMorgan - 对于字符数据,当然,好点。旧习难改。 2001 年我开始这项工作时,我对 Unicode 的了解为零。虽然这不仅仅是字符数据,但它在标题中包含了比字节顺序更多的信息。它现在实际上已简化为当前格式的 0 或 1。我的目标是使用一种在以各种方式交换时可识别的位模式。我明白为什么现在它是一个糟糕的选择,以及为什么 FEFF 是一个好的选择。

标签: io coding-style rust endianness idioms


【解决方案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);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多