提问人:Thomas Mueller 提问时间:11/15/2023 最后编辑:Thomas Mueller 更新时间:11/16/2023 访问量:70
在 Rust 中,我想从流或文件中读取以填充缓冲区,并检测 EOF
In Rust, I want to read from a stream or file to fill a buffer, and detect EOF
问:
在 Rust 中,我想(使用 BufReader)读取缓冲区数组来填充它。我想读取确切的字节数,但在 EOF 的情况下除外,在这种情况下,读取更少就可以了。我自己实现了一个帮助程序方法,如下所示,并且有效。但是,我想知道是否没有方便的方法已经做到了这一点。
pub fn read_fully<R: Read>(read: &mut R, buffer: &mut [u8]) -> Result<usize, Error> {
let mut count: usize = 0;
loop {
let r = read.read(&mut buffer[count..])?;
if r == 0 {
return Ok(count);
}
count += r;
}
}
对于我发现的每种现有方法,似乎都存在一个问题:
- “read”可以少读(例如,对于 stdin)。
- “read_exact”不适用于 EOF。
- “read_to_end”需要一个 Vec 而不是一个数组,并且会读取所有内容,可能会扩展向量。
答:
0赞
Chayim Friedman
11/15/2023
#1
这里有一个想法,我不确定它是否比你的更好,但它也有效:
pub fn read_fully<R: Read>(read: &mut R, buffer: &mut [u8]) -> Result<usize, Error> {
let mut data = Vec::with_capacity(buffer.len());
read.take(buffer.len().try_into().unwrap())
.read_to_end(&mut data)?;
buffer[..data.len()].copy_from_slice(&data);
Ok(data.len())
}
它的效率可能会低得多。是否更清楚由您决定。
评论
0赞
Thomas Mueller
11/15/2023
是的,我希望该方法是有效的(没有memcpy)。冗长很好。
0赞
Thomas Mueller
11/15/2023
#2
似乎应该忽略ErrorKind::Interrupted。因此,解决方案将变为:
pub fn read_fully<R: Read>(mut read: R, buffer: &mut [u8]) -> Result<usize, Error> {
let mut count: usize = 0;
loop {
let r = read.read(&mut buffer[count..]);
match r {
Ok(0) => {
return Ok(count)
},
Ok(x) => {
count += x
},
Err(e) => {
if e.kind() == ErrorKind::Interrupted {
// retry
} else {
return Err(e);
}
}
};
}
}
1赞
Chayim Friedman
11/16/2023
#3
以下是使用实验性 API 的更短、更简洁的方法:
#![feature(read_buf, core_io_borrowed_buf)]
use std::io::{BorrowedBuf, Error, ErrorKind, Read};
pub fn read_fully<R: Read>(read: &mut R, buffer: &mut [u8]) -> Result<usize, Error> {
let mut buffer = BorrowedBuf::from(buffer);
match read.read_buf_exact(buffer.unfilled()) {
Ok(()) => {}
Err(err) if err.kind() == ErrorKind::UnexpectedEof => {}
Err(err) => return Err(err),
}
Ok(buffer.len())
}
此时,您可能只想将 a 作为参数:BorrowedCursor
#![feature(read_buf, core_io_borrowed_buf)]
use std::io::{BorrowedCursor, Error, ErrorKind, Read};
pub fn read_fully<R: Read>(read: &mut R, buffer: BorrowedCursor<'_>) -> Result<(), Error> {
match read.read_buf_exact(buffer) {
Err(err) if err.kind() == ErrorKind::UnexpectedEof => Ok(()),
v => v,
}
}
这允许使用未初始化的缓冲区等简洁操作。
评论
0赞
Thomas Mueller
11/17/2023
谢谢,有趣!一旦它不再是实验性的,我就会使用它
评论
read_to_end()
不是你想要的。在文件结束之前,它将读取比所需字节更多的字节。我不认为您可以使用其他方法,您的自定义代码很好。ErrorKind::Interrupted
R: Read
&mut R
mut
mut read: R