从实现 Read 的类型中读取任意数量的字节
Read an arbitrary number of bytes from type implementing Read
我有东西是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
(而且我不太确定为什么需要它)。
我想我可以用 BufReader
替换 File
并用 fill_buf
和 consume
跳舞,这听起来很复杂,但我仍然想知道:我是否忽略了什么?
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
,如果不是的话就往buffer里读更多的数据
2。迭代器版本
您的第二个解决方案更好,因为您不必检查已读取了多少字节,也不必重新读取以防万一count != length
。您需要在 Read
特征上使用 bytes()
函数(由 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);
}
您总是可以使用一些 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()
方法不能保证填充整个切片。它有可能 return 字节数小于切片长度。有几个关于添加方法来填补这个空白的 RFC,例如,this 一个。
与迭代器适配器一样,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();
}
我有东西是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
(而且我不太确定为什么需要它)。
我想我可以用 BufReader
替换 File
并用 fill_buf
和 consume
跳舞,这听起来很复杂,但我仍然想知道:我是否忽略了什么?
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
,如果不是的话就往buffer里读更多的数据
2。迭代器版本
您的第二个解决方案更好,因为您不必检查已读取了多少字节,也不必重新读取以防万一count != length
。您需要在 Read
特征上使用 bytes()
函数(由 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);
}
您总是可以使用一些 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()
方法不能保证填充整个切片。它有可能 return 字节数小于切片长度。有几个关于添加方法来填补这个空白的 RFC,例如,this 一个。
与迭代器适配器一样,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();
}