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

mus*_*iKk 5 io rust

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

所以我尝试了这个:

let mut vec = Vec::with_capacity(length);
let count = file.read(vec.as_mut_slice()).unwrap();
Run Code Online (Sandbox Code Playgroud)

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();
Run Code Online (Sandbox Code Playgroud)

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

我想我可以代替File使用BufReader和舞蹈周围fill_bufconsume这听起来够复杂了,但我还是纳闷:难道我忽略了什么?

She*_*ter 5

与迭代器适配器一样,IO 适配器self按值获取尽可能高效。与迭代器适配器一样,对 a 的可变引用Read也是 a 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();
}
Run Code Online (Sandbox Code Playgroud)


mdu*_*dup 3

1. 填充向量版本

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

let mut vec = vec![0u8; length];
Run Code Online (Sandbox Code Playgroud)

以下完整代码有效:

#![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);
}
Run Code Online (Sandbox Code Playgroud)

当然,您仍然需要检查是否count == length,如果不是,则将更多数据读入缓冲区。


2.迭代器版本

您的第二个解决方案更好,因为您不必检查已读取了多少字节,并且不必重新读取 case 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);
}
Run Code Online (Sandbox Code Playgroud)