2014-10-09 42 views
2

好愚蠢noob問題,但我顯然缺少文檔中的東西。我應該如何閱讀關於endianess的文件內容?

我可以看到,在防鏽,我可以讀取文件到字節數組:

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

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

我還可以有big endian和little endian格式閱讀只是一個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()); 
} 

更多的建議嗎?這已經看起來好多了。

+0

它不是_that_難看。如果你想看到醜陋的下載Parrot虛擬機的源代碼,並看看我在C中做了什麼。:)嚴肅地說,如果你不想看它,就把它抽象出來。我透明地檢測字節順序的方式是在文件頭存儲一個幻數(如1234),並在運行時使用它來檢測字節順序。至於原始的,Rust已經提供它們。 (File :: read_be_u32等) – codenheim 2014-10-09 20:47:27

+1

爲了提高效率,你需要將分支提取出循環 - 可能一直到模板參數。 '黃金'鏈接器做到了這一點,它是*巨大*。 – o11c 2014-10-09 21:05:22

+0

@codenheim:U + FEFF是標準BOM,在這種情況下,我認爲這是一個不錯的選擇。 – 2014-10-09 21:24:52

回答

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); 
}