tokio::io::copy
不提供进度更新回调。当copy
需要很长时间才能完成时,最好报告复制操作的进度。复制发生时,是否有方法获取状态/进度?
tokio::io::copy
函数只处理AsyncRead
和AsyncWrite
特性。我不确定是否有任何预先构建的东西,但编写自己的适配器来显示进度也不错:
use std::io::Result;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::time::Duration;
use pin_project::pin_project;
use tokio::io::{AsyncRead, ReadBuf};
use tokio::time::{interval, Interval};
#[pin_project]
pub struct ProgressReadAdapter<R: AsyncRead> {
#[pin]
inner: R,
interval: Interval,
interval_bytes: usize,
}
impl<R: AsyncRead> ProgressReadAdapter<R> {
pub fn new(inner: R) -> Self {
Self {
inner,
interval: interval(Duration::from_millis(100)),
interval_bytes: 0,
}
}
}
impl<R: AsyncRead> AsyncRead for ProgressReadAdapter<R> {
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut ReadBuf<'_>,
) -> Poll<Result<()>> {
let this = self.project();
let before = buf.filled().len();
let result = this.inner.poll_read(cx, buf);
let after = buf.filled().len();
*this.interval_bytes += after - before;
match this.interval.poll_tick(cx) {
Poll::Pending => {}
Poll::Ready(_) => {
println!("reading at {} bytes per second", *this.interval_bytes * 10);
*this.interval_bytes = 0;
}
};
result
}
}
然后可以这样使用:
use tokio::fs::File;
#[tokio::main]
async fn main() -> Result<()> {
let mut file1 = File::open("foo.bin").await?;
let mut file2 = File::create("bar.bin").await?;
let mut file1 = ProgressReadAdapter::new(file1);
tokio::io::copy(&mut file1, &mut file2).await?;
Ok(())
}
reading at 38338560 bytes per second
reading at 315146240 bytes per second
reading at 422625280 bytes per second
reading at 497827840 bytes per second
reading at 428605440 bytes per second
你可能会把它挂起来,表明它是否更可配置,让它看起来更好,但我将把它留给读者练习。