从实现Read的类型中读取任意数量的字节

时间:2015-07-19 13:49:37

标签: io rust

我有Read的东西;目前它是File。我想从中读取一些仅在运行时已知的字节(二进制数据结构中的长度前缀)。

所以我尝试了这个:

let mut vec = Vec::with_capacity(length);
let count = file.read(vec.as_mut_slice()).unwrap();

count为零,因为vec.as_mut_slice().len()也为零。

[0u8;length]当然不起作用,因为必须在编译时知道大小。

我想做

let mut vec = Vec::with_capacity(length);
let count = file.take(length).read_to_end(vec).unwrap();

但是take的接收者参数是T而我只有&mut T(而且我还不确定为什么它仍然需要)。

我想我可以用File替换BufReader并与fill_bufconsume一起跳舞,听起来很复杂但我仍然想知道:我忽略了什么吗?

3 个答案:

答案 0 :(得分:4)

与Iterator适配器一样,IO适配器按值self尽可能高效。与Iterator适配器一样,对Read的可变引用也是Read

要解决您的问题,您只需要Read::by_ref

use std::io::Read;
use std::fs::File;

fn main() {
    let mut file = File::open("/etc/hosts").unwrap();
    let length = 5;

    let mut vec = Vec::with_capacity(length);
    file.by_ref().take(length as u64).read_to_end(&mut vec).unwrap();

    let mut the_rest = Vec::new();
    file.read_to_end(&mut the_rest).unwrap();
}

答案 1 :(得分:1)

1。填充此矢量版本

你的第一个解决方案即将开始。你确定了问题,但没有尝试解决它!问题是无论向量的容量如何,它仍然是空的(vec.len() == 0)。相反,您实际上可以用空元素填充它,例如:

let mut vec = vec![0u8; length];

以下完整代码有效:

#![feature(convert)] // needed for `as_mut_slice()` as of 2015-07-19

use std::fs::File;
use std::io::Read;

fn main() {
    let mut file = File::open("/usr/share/dict/words").unwrap();
    let length: usize = 100;
    let mut vec = vec![0u8; length];
    let count = file.read(vec.as_mut_slice()).unwrap();
    println!("read {} bytes.", count);
    println!("vec = {:?}", vec);
}

当然,你仍然需要检查是否count == length,如果不是这样的话,可以在缓冲区中读取更多数据。

2。迭代器版本

您的第二个解决方案更好,因为您不必检查已读取的字节数,并且在count != length的情况下您不必重新读取。您需要在bytes()特征上使用Read函数(由File实现)。这将文件转换为流(即迭代器)。由于错误仍然可能发生,因此您不会获得Iterator<Item=u8>而是Iterator<Item=Result<u8, R::Err>>。因此,您需要在迭代器中明确地处理失败。为简单起见,我们将在此处使用unwrap()

use std::fs::File;
use std::io::Read;

fn main() {
    let file = File::open("/usr/share/dict/words").unwrap();
    let length: usize = 100;
    let vec: Vec<u8> = file
        .bytes()
        .take(length)
        .map(|r: Result<u8, _>| r.unwrap()) // or deal explicitly with failure!
        .collect();
    println!("vec = {:?}", vec);
}

答案 2 :(得分:1)

您始终可以使用unsafe位来创建未初始化内存的向量。使用原始类型是完全安全的:

let mut v: Vec<u8> = Vec::with_capacity(length);
unsafe { v.set_len(length); }
let count = file.read(vec.as_mut_slice()).unwrap();

这样,vec.len()将被设置为其容量,并且其中的所有字节都将是未初始化的(可能是零,但可能是一些垃圾)。这样就可以避免将内存归零,这对于原始类型来说非常安全。

请注意,read()上的Read方法无法保证填满整个切片。它可能以小于片长度的字节数返回。有几个RFC在添加方法来填补这个空白,例如,this一个。