我如何告诉 Rust 中的 std::io::copy 停止阅读并完成写作?

How do I tell std::io::copy in Rust to stop reading and finish up writing?

我正在通过 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");
}

正如评论所说,io::copy 是一种方便的功能,可以完整读取 Reader 并将其内容写入 Writer 而不会在两者之间停止;它用于当您 关心中间状态但只想将整个内容从 reader 发送给作者时。

如果您只想要 response 的前几 Kb,您可以使用 io::Read::take,它将 Reader 限制为您指定的任何限制。它将 return 一个新的 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");
}