-
-
Notifications
You must be signed in to change notification settings - Fork 4
SFTP Examples
SFTP is a file transfer protocol designed as an extension of the SSH2 protocol. Despite similar names and features, SFTP is not related to the File Transfer Protocol (FTP/FTPS). If you need to tunnel a FTP session through SSH then refer to the section on TCP tunneling.
The specification of the SFTP protocol was never finished, and there are some questionable design choices in the drafts that are most commonly used. The most important of these are the maximum packet size (32KB) and the requirement that each SFTP packet be individually acknowledged before the next one is sent. Combined, these factors can create a bottleneck that slows down SFTP transfers, particularly on connections with high latency. Recent versions of libssh2 try to mitigate this by dispatching several packets at a time without waiting for the acknowledgement, so to achieve maximum throughput you should try to read/write at least (and preferably an exact multiple of) 32KB at a time.
- Download
- Upload
- Read file permissions
- Write file permissions
- List directory
- Recursive download
- Recursive upload
This example downloads a file over SFTP. For extended features like reading file metadata refer to the SFTPStream class:
Dim session As SSH.Session = SSH.Connect("ssh://user:[email protected]/")
Dim sftp As New SSH.SFTPSession(session)
Dim reader As SSHStream = sftp.Get("file.txt")
Dim writer As BinaryStream = BinaryStream.Create(SpecialFolder.Desktop.Child("file.txt"))
Do Until reader.EOF()
writer.Write(reader.Read(1024 * 1024 * 32))
Loop
reader.Close()
writer.Close()
This example uploads a file over SFTP. For extended features like writing file metadata refer to the SFTPStream class:
Dim session As SSH.Session = SSH.Connect("ssh://user:[email protected]/")
Dim sftp As New SSH.SFTPSession(session)
Dim writer As SSHStream = sftp.Put("file.txt")
Dim reader As BinaryStream = BinaryStream.Open(SpecialFolder.Desktop.Child("file.txt"))
Do Until reader.EOF()
writer.Write(reader.Read(1024 * 1024 * 32))
Loop
reader.Close()
writer.Close()
This example reads the Unix-style permissions of a file on the server:
Dim session As SSH.Session = SSH.Connect("ssh://user:[email protected]/")
Dim sftp As New SSH.SFTPSession(session)
If sftp.PathExists("/path/to/the/file.txt") Then
Dim stream As SSH.SFTPStream = sftp.Get("/path/to/the/file.txt")
Dim perms As Permissions = stream.Mode
End If
This example updates the Unix-style permissions of a file on the server:
Dim session As SSH.Session = SSH.Connect("ssh://user:[email protected]/")
Dim sftp As New SSH.SFTPSession(session)
If sftp.PathExists("/path/to/the/file.txt") Then
Dim stream As SSH.SFTPStream = sftp.Append("/path/to/the/file.txt")
stream.Mode = New Permissions(&o744)
End If
This example uses the SFTPDirectory class to get the names of files/subdirectories in a remote directory using SFTP:
Dim session As SSH.Session = SSH.Connect("ssh://user:[email protected]/")
Dim sftp As New SSH.SFTPSession(session)
Dim names() As String
Dim lister As SSH.SFTPDirectory = sftp.ListDirectory("/path/to/dir/")
Do
names.Append(lister.CurrentName)
Loop Until Not lister.ReadNextEntry()
lister.Close()
This example uses the SFTPTransferQueue class to manage simultaneous downloads while recursively downloading a remote directory tree.
Sub DownloadDirectory(Session As SSH.SFTPSession, Queue As SSH.SFTPTransferQueue, DirectoryPath As String, LocalDirectory As FolderItem, Optional RelativeRoot As String)
' normalize the DirectoryPath
If Right(DirectoryPath, 1) <> "/" Then DirectoryPath = DirectoryPath + "/"
If RelativeRoot = "" Then RelativeRoot = DirectoryPath
Dim relativepath As String = Replace(DirectoryPath, RelativeRoot, "")
' locate or create the corresponding local directory
Dim thisdir As FolderItem = LocalDirectory
Dim path() As String = relativepath.Split("/")
For i As Integer = 0 To UBound(path)
If path(i).Trim = "" Then Continue
thisdir = thisdir.Child(path(i))
If thisdir.Directory Then Continue
If thisdir.Exists Then Raise New IOException ' file exists with the name of a directory we need
thisdir.CreateAsFolder()
Next
Dim startcount As Integer = Queue.Count
' begin listing the contents of DirectoryPath
Dim lister As SSH.SFTPDirectory = Session.ListDirectory(DirectoryPath)
Do
Select Case lister.CurrentType
Case SSH.SFTPEntryType.Unknown
' skip. Either a weird custom type or the directory is empty
Continue
Case SSH.SFTPEntryType.Directory
' recurse into the subdirectory
DownloadDirectory(Session, Queue, DirectoryPath + lister.CurrentName, LocalDirectory, RelativeRoot)
Else
' prepare the download
Dim reader As SSH.SFTPStream = lister.OpenFile()
Dim file As FolderItem = thisdir.Child(lister.CurrentName)
Dim writer As BinaryStream = BinaryStream.Create(file)
' run the queue for a bit if needed
Do Until Queue.Count < Queue.MaxCount
If Not Queue.PerformOnce() Then Exit Do
Loop
' add the download to the queue
Queue.AddDownload(reader, writer)
End Select
Loop Until Not lister.ReadNextEntry()
lister.Close()
' run the queue until there are fewer downloads remaining than we started with
Do Until Queue.Count <= startcount
If Not Queue.PerformOnce() Then Exit Do
Loop
End Sub
Usage example:
Dim session As SSH.Session = SSH.Connect("ssh://user:[email protected]/")
Dim sftp As New SSH.SFTPSession(session)
Dim queue As New SSH.SFTPTransferQueue
Dim localroot As FolderItem = SelectFolder()
DownloadDirectory(sftp, queue, "/home/username/example/", localroot)
This example uses the SFTPTransferQueue class to manage simultaneous uploads while recursively uploading a local directory tree.
Sub UploadDirectory(Session As SSH.SFTPSession, Queue As SSH.SFTPTransferQueue, DirectoryPath As String, LocalDirectory As FolderItem)
' Normalize the DirectoryPath and create the remote directory if needed
If Right(DirectoryPath, 1) <> "/" Then DirectoryPath = DirectoryPath + "/"
If Not Session.PathExists(DirectoryPath) Then
Session.MakeDirectory(DirectoryPath)
End If
Dim startcount As Integer = Queue.Count
' begin listing the contents of LocalDirectory
Dim c As Integer = LocalDirectory.Count
For i As Integer = 1 To c
Dim item As FolderItem = LocalDirectory.Item(i)
If item.Directory Then
' recurse into the subdirectory
UploadDirectory(Session, Queue, DirectoryPath + item.Name, item)
Else
' prepare the upload
Dim reader As BinaryStream = BinaryStream.Open(item)
Dim writer As SSH.SFTPStream = Session.Put(DirectoryPath + item.Name)
' run the queue for a bit if needed
Do Until Queue.Count < Queue.MaxCount
If Not Queue.PerformOnce() Then Exit Do
Loop
' add the upload to the queue
Queue.AddUpload(writer, reader)
End If
Next
' run the queue until there are fewer uploads remaining than we started with
Do Until Queue.Count <= startcount
If Not Queue.PerformOnce() Then Exit Do
Loop
End Sub
Usage example:
Dim session As SSH.Session = SSH.Connect("ssh://user:[email protected]/")
Dim sftp As New SSH.SFTPSession(session)
Dim queue As New SSH.SFTPTransferQueue
Dim localroot As FolderItem = SelectFolder()
UploadDirectory(sftp, queue, "/home/user/example/", localroot)
Wiki home | Project page | Bugs | Become a sponsor
Text and code examples are Copyright ©2018-24 Andrew Lambert, offered under the CC BY-SA 3.0 License.