Search code examples
ruststreamssh2

How can I write a ssh2::Stream to a file without reading the data into memory?


I am trying to download a large binary file via SCP using ssh2 crate v0.3.3.

extern crate ssh2;

use std::net::TcpStream;
use ssh2::Session;
use std::path::Path;
use std::fs::File;
use indicatif::ProgressBar;

fn main() -> Result<(), Box<std::error::Error>> {
    let ssh_host_port = "prokerala.com:22";
    let ssh_user = "prokeral";
    let remote_temp_file = "/tmp/dbimport_Rk6Iwwm5.sql.bz2";

    let tcp = TcpStream::connect(&ssh_host_port).unwrap();
    let mut sess = Session::new().unwrap();
    sess.handshake(&tcp).expect("SSH handshake failed");
    let _ = sess.userauth_agent(ssh_user);

    let path = Path::new(&remote_temp_file);
    let (mut remote_file, stat) = sess.scp_recv(path).unwrap();

    let stream:ssh2::Stream = remote_file.stream(1);

    // Update: solved by using io::copy as suggested by @apemanzilla below
    // let mut target = File::create("/tmp/done.txt").unwrap();
    // let pb = ProgressBar::new(stat.size());
    // std::io::copy(&mut pb.wrap_read(remote_file), &mut target)?;
    Ok(())
}

I want to write stream to a file, and show a progress bar. Is it possible to write stream to a file directly, without reading the data into memory with stream.read() within a loop?


Solution

  • Since Stream implements Read, you should be able to just use std::io::copy(&mut stream, &mut File::create(...).unwrap()) to copy all the data into a file. If you want a progress bar, I'd recommend using the indicatif crate, which has a method to wrap a Read instance, automatically updating a progress bar as data is read.