首页 > 解决方案 > 如何告诉 Rust 中的 std::io::copy 停止读取并完成写入?

问题描述

我正在通过 Rust 直接下载 MP3 音频流。由于这个流是不确定的,我希望能够提前取消它以保存我到目前为止下载的内容。目前,我通过按 CTRL + C 来停止程序。这会生成一个 stream.mp3 文件,然后我可以播放和收听,虽然这可行,但并不理想。

给定以下代码,我如何以编程方式io::copy()提前停止并让它保存文件而不杀死整个程序?

extern crate reqwest;

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

// Note that this is a direct link to the stream, not a webpage with HTML and a stream
const STREAM_URL: &str = "http://path.to/stream";

fn main() {
    let mut response = reqwest::get(STREAM_URL)
        .expect("Failed to request mp3 stream");
    let mut output = File::create("stream.mp3")
        .expect("Failed to create file!");
    io::copy(&mut response, &mut output)
        .expect("Failed to copy mp3 stream to file");
}

标签: httpioruststreamreqwest

解决方案


正如评论所说,io::copy这是一个方便的功能,可以Reader完整地阅读 a 并将其内容写入 aWriter而不会在两者之间停下来;它用于当您关心中间状态而只想将整个事物从阅读器运送到作者时。

如果您只想要 的前几个 Kb,则response可以使用io::Read::take,它将 限制为Reader您指定的任何限制。它将返回一个新的Reader,您可以将其传递给io::copy.

是的,您可以在任意位置剪切 MP3 文件。它是一种帧格式,虽然您很可能会破坏最后一帧,但实际上所有 mp3 解码器都能够处理这种情况。


一些合乎情调的东西

// `Read` needs to be in scope, so .take() is available on a `io::Read`
use std::io::Read;
use std::io;
use std::fs::File;

fn main() {
    let mut response = reqwest::get(STREAM_URL)
        .expect("Failed to request mp3 stream")
        .take(100*1024);  // Since `Response` is `Read`, we can `take` from it.
    let mut output = File::create("stream.mp3")
        .expect("Failed to create file!");
    // `response` is a limited reader, so it will only read 100kb before
    // returning EOF, signaling a successful completion to `copy`.
    io::copy(&mut response, &mut output)
        .expect("Failed to copy mp3 stream to file");
}

推荐阅读