Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Streaming a file from SharpSSH

I'm trying to use SharpSSH to get a file from a remote SFTP server, and I want to read it out as a stream.

I found:

  • class Sftp, which has a Get method that saves it to a local file -- close

  • class SshStream, which might do kind of what I want, but seems disjoint from Sftp so I might have to implement the SFTP part myself (??)

  • class ChannelSftp, which implements SFTP methods like get(String, OutputStream), which seems perfect, except it's a low-level class and it's not at all obvious to me how to even instantiate it

It looks like if Sftp's ChannelSftp SftpChannel property wasn't private, I could use that and everything would be perfect. I'd like to avoid hacking up SharpSSH if possible, though.

Am I missing something?

like image 647
Ken Avatar asked Jul 21 '10 00:07

Ken


1 Answers

I worked something out, and tested it out. Give it a try, and feel free to massage the API.

First off, you will need to surface up a method that allows you to take advantage of the ChannelSftp methods that call for OutputStreams instead of destination file names. If you don't want to use reflection to do it, then add this method to the Sftp class and recompile SharpSSH.

public void GetWithStream(string fromFilePath, Tamir.SharpSsh.java.io.OutputStream stream)
{
    cancelled = false;
    SftpChannel.get(fromFilePath, stream, m_monitor);
}

Next, create a wrapper for the Stream class that is compatible with Tamir.SharpSsh.java.io.OutputStream, such as the one below:

using System.IO;
using Tamir.SharpSsh.java.io;

public class GenericSftpOutputStream : OutputStream
{
    Stream stream;
    public GenericSftpOutputStream(Stream stream)
    {
        this.stream = stream;
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        stream.Write(buffer, offset, count);
    }

    public override void Flush()
    {
        stream.Flush();
    }

    public override void Close()
    {
        stream.Close();
    }

    public override bool CanSeek
    {
        get { return stream.CanSeek; }
    }

    public override long Seek(long offset, SeekOrigin origin)
    {
        return stream.Seek(offset, origin);
    }

    protected override void Dispose(bool disposing)
    {
        base.Dispose(disposing);

        if (this.stream != null)
        {
            this.stream.Dispose();
            this.stream = null;
        }
    }
}

With those ingredients, you can now use OpenSSH to stream its data to the stream of your choice, as demonstrated below with a FileStream.

using System.IO; using Tamir.SharpSsh;

class Program
{
    static void Main(string[] args)
    {
        var host = "hostname";
        var user = "username";
        var pass = "password";
        var file = "/some/remote/path.txt";
        var saveas = @"C:\some\local\path";

        var client = new Sftp(host, user, pass);
        client.Connect();

        using (var target = new GenericSftpOutputStream(File.Open(saveas, FileMode.OpenOrCreate)))
        {
            client.GetWithStream(file, target);
        }

        client.Close();
    }
}
like image 77
kbrimington Avatar answered Nov 17 '22 14:11

kbrimington