More .NET components

Single file operations

Single-file upload and download #

Use PutFile method to upload a single file, and GetFile method to download it. Both methods require a target name, which means it's possible to use a different target file name if needed.

CSharp

// upload a local file to server
sftp.PutFile(@"C:\MyData\file.txt", "/MyData/file.txt");

// download from server to a local file using a different name
sftp.GetFile("/MyData/file.txt", @"C:\MyData\copy-file.txt");

VisualBasic

' upload a local file to server
sftp.PutFile("C:\MyData\file.txt", "/MyData/file.txt")

' download from server to a local file using a different name
sftp.GetFile("/MyData/file.txt", "C:\MyData\copy-file.txt")

These methods overwrite any existing files. To check whether a remote file exists, use FileExists method.

Tip: For uploading or downloading multiple files, use Upload and Download methods. They accept single-file input as well and support both single-file and multi-file transfers.

Stream-based upload and download #

Both PutFile and GetFile methods accept a System.IO.Stream object, making it possible to transfer data from/to any kind of stream.

For example, use MemoryStream when processing data in memory, without having to create temporary disk files:

Upload from memory:

CSharp

// prepare data
byte[] data = System.Text.Encoding.UTF8.GetBytes("test data");

// convert data to a memory stream
var stream = new MemoryStream(data);

// upload data from memory
sftp.PutFile(stream, "/MyData/file.txt");

VisualBasic

' prepare data
Dim data() As Byte = System.Text.Encoding.UTF8.GetBytes("test data")

' convert data to a memory stream
Dim stream As New MemoryStream(data)

' upload data from memory
sftp.PutFile(stream, "/MyData/file.txt")

Download to memory:

CSharp

// download a remote file into a memory stream
var stream = new MemoryStream();
sftp.GetFile("/MyData/file.txt", stream);

// convert memory stream to data
byte[] data = stream.ToArray();

VisualBasic

' download a remote file into a memory stream
Dim stream As New MemoryStream()
sftp.GetFile("/MyData/file.txt", stream)

' convert memory stream to data
Dim data() As Byte = stream.ToArray()

Deleting a file #

To delete a remote file, use DeleteFile method.

For example, to delete a remote file that doesn't exist locally, use the following code:

CSharp

// if local file is deleted
if (!File.Exists(@"C:\MyData\file.txt"))
{
    // delete remote file as well
    sftp.DeleteFile("/MyData/file.txt");
}

VisualBasic

' if local file is deleted
If Not File.Exists("C:\MyData\file.txt") Then
    ' delete remote file as well
    sftp.DeleteFile("/MyData/file.txt")
End If

Tip: For deleting multiple files or non-empty directories, use Delete method.

Rename/move a file #

To rename a remote file or directory, use Rename method. It can also be used for moving a remote file or directory to another location on the file system of the remote host.

CSharp

// rename a remote file
sftp.Rename("/MyData/a.txt", "/MyData/b.txt");

// move a remote file
sftp.Rename("/MyData/file.txt", "/Backups/file.txt");

VisualBasic

' rename a remote file
sftp.Rename("/MyData/a.txt", "/MyData/b.txt")

' move a remote file
sftp.Rename("/MyData/file.txt", "/Backups/file.txt")

Tip: For moving files between client and server, use Upload or Download methods with the TransferMethod.Move argument specified.

Atomic POSIX rename #

SFTP protocol's rename operation fails when the target file already exists. This poses a problem for Unix-like filesystems based on POSIX standard, which specifies that the target file is deleted if it already exists.

Because of this, Unix-based SFTP servers can't implement SFTP rename command using Unix's POSIX-like rename function, but have to work around the difference by creating a hard link using the new name, followed by removing the original name. Unfortunately, this approach fails on filesystems that don't support hard links (such as FAT).

Another problem with this approach is that SFTP rename is not atomic because it consists of two operations, unlike POSIX rename function.

To solve these issues, a 'posix-rename' extension was introduced in OpenSSH 4.8 and has been implemented by other SFTP servers as well. To use this extension (when available), just set Sftp object's Settings.UsePosixRename property to true.

CSharp

// use 'Posix rename' when available
sftp.Settings.UsePosixRename = true;

// rename a remote file
sftp.Rename("/MyData/a.txt", "/MyData/b.txt");

VisualBasic

' use 'Posix rename' when available
sftp.Settings.UsePosixRename = True

' rename a remote file
sftp.Rename("/MyData/a.txt", "/MyData/b.txt")

Checking file existence #

To check whether a remote file already exists, use FileExists method.

This is useful, for example, when you are about to upload a file, but would like to ask the user whether to overwrite an existing target file first:

CSharp

// check whether a remote file exists
bool exists = sftp.FileExists("/MyData/file.txt");

if (exists)
{
    // prompt the user
    // ...
}

VisualBasic

' check whether a remote file exists
Dim exists = sftp.FileExists("/MyData/file.txt")

If exists Then
    ' prompt the user
    ' ...
End If
Tip: Upload or Download methods have built-in overwrite mode support.

Getting file length #

To retrieve the length of a remote file, use GetFileLength method:.

This can be used to determine the current remote file length when resuming a broken transfer or in order to ask the user for permission before downloading a large file over a slow network:

CSharp

// get the length of a remote file
long length = sftp.GetFileLength("/MyData/file.txt");

// large downloads need user permission
if (length > 1024 * 1024)
{
    // prompt the user what to do with file > 1 MB
    // ...
}

VisualBasic

' get the length of a remote file
Dim length = sftp.GetFileLength("/MyData/file.txt")

' large downloads need user permission
If length > 1024 * 1024 Then
    ' prompt the user what to do with file > 1 MB
    ' ...
End If

Getting and setting file date/time #

To retrieve the last modification date/time of a remote file, use GetFileDateTime method. To set it, use SetFileDateTime method.

Getting remote time

CSharp

string localPath = @"C:\MyData\file.txt";
string remotePath = "/MyData/file.txt";
DateTime remoteTime = sftp.GetFileDateTime(remotePath);

// download file and set local time appropriately
sftp.GetFile(remotePath, localPath);
File.SetLastWriteTime(localPath, remoteTime);

VisualBasic

Dim localPath = "C:\MyData\file.txt"
Dim remotePath = "/MyData/file.txt"
Dim remoteTime = sftp.GetFileDateTime(remotePath)

' download file and set local time appropriately
sftp.GetFile(remotePath, localPath)
File.SetLastWriteTime(localPath, remoteTime)

Setting remote time

CSharp

string localPath = @"C:\MyData\file.txt";
string remotePath = "/MyData/file.txt";
DateTime localTime = new FileInfo(localPath).LastWriteTime;

// upload file and set remote time appropriately
sftp.PutFile(localPath, remotePath);
sftp.SetFileDateTime(remotePath, localTime);

VisualBasic

Dim localPath = "C:\MyData\file.txt"
Dim remotePath = "/MyData/file.txt"
Dim localTime = New FileInfo(localPath).LastWriteTime

' upload file and set remote time appropriately
sftp.PutFile(localPath, remotePath)
sftp.SetFileDateTime(remotePath, localTime)

Getting file checksums #

To make it possible to verify the file has been transferred correctly, some SFTP servers support checksum calculation (via the 'check-file' SFTP extension), making it possible to compare checksums of local and remote files.

CSharp

string localPath = @"C:\MyData\file.txt";
string remotePath = "file.txt";

// upload the file
sftp.PutFile(localPath, remotePath);

// compute checksums
var checksumAlgorithm = ChecksumAlgorithm.SHA256;
string remoteChecksum = sftp.GetChecksum(remotePath, checksumAlgorithm);
string localChecksum = LocalItem.GetChecksum(localPath, checksumAlgorithm);

// compare checksums
if (remoteChecksum == localChecksum)
    Console.WriteLine("File uploaded and verified.");
else
    Console.WriteLine("File uploaded with errors.");

VisualBasic

Dim localPath = "C:\MyData\file.txt"
Dim remotePath = "file.txt"

' upload the file
sftp.PutFile(localPath, remotePath)

' compute checksums
Dim checksumAlgorithm As ChecksumAlgorithm = ChecksumAlgorithm.SHA256
Dim remoteChecksum As String = sftp.GetChecksum(remotePath, checksumAlgorithm)
Dim localChecksum As String = LocalItem.GetChecksum(localPath, checksumAlgorithm)

' compare checksums
If remoteChecksum = localChecksum Then
    Console.WriteLine("File uploaded and verified.")
Else
    Console.WriteLine("File uploaded with errors.")
End If

SSH has reliable built-in integrity checks, which mostly makes it unnecessary to verify transferred files using checksums.

Working with file attributes #

SFTP protocol makes it possible to retrieve or set several file and directory attributes:

  • Last modification time
  • Last access time
  • Creation time
  • Permissions
  • Owner and group

These are accessible through properties of SftpItem object, which can be retrieved by calling GetInfo, GetList or GetItems methods.

To set these attributes, create an instance of SftpAttributes object, set its properties and pass it to SetAttributes method.

The following code snippet shows how to grant other users write access to a file:

CSharp

// get the info about a remote file
SftpItem item = sftp.GetInfo("/MyData/file.txt");

// prepare attributes (allow others to write as well)
SftpAttributes attributes = new SftpAttributes();
attributes.Permissions = item.Permissions | SftpPermissions.OthersWrite;

// set the file attributes
sftp.SetAttributes("/MyData/file.txt", attributes);

VisualBasic

' get the info about a remote file
Dim item = sftp.GetInfo("/MyData/file.txt")

' prepare attributes (allow others to write as well)
Dim attributes = New SftpAttributes()
attributes.Permissions = item.Permissions Or SftpPermissions.OthersWrite

' set the file attributes
sftp.SetAttributes("/MyData/file.txt", attributes)

Please note that not all SFTP servers support all the attributes.

Creating symlinks #

To create a symbolic link, use CreateSymlink method:

CSharp

// create a symlink
sftp.CreateSymlink("link.txt", "/MyData/file.txt");

VisualBasic

' create a symlink
sftp.CreateSymlink("link.txt", "/MyData/file.txt")

Resolving symlinks #

To retrieve the target path of a symbolic link, use ResolveSymlink method:

CSharp

// get the symlink target's real path
string realPath = sftp.ResolveSymlink("link.txt");

// display the target of the link to the user
// ...

VisualBasic

' get real path of the symbolic link
Dim realPath = sftp.ResolveSymlink("/MyData/link.txt")

' display the target of the link to the user
' ...

Partial file transfer (appending) #

GetFile and PutFile methods make it possible to download or upload a part of a file. This is often used for appending data to an existing file, or to resume broken transfers. Of course, it is possible to write/read data to/from any other position in a file as well.

To upload and download specific file part, use three additional parameters: local offset, remote offset and number of bytes you want to transfer. Local offset is not required for stream-based methods - data is read/written from/to the current stream position.

CSharp

string localPath = @"C:\MyData\part7.txt";
string remotePath = "/MyData/summary.txt";
string header = string.Format("<FILE>: {0}\n", localPath);
long localFileLength = new FileInfo(localPath).Length;
long remoteFileLength = sftp.GetFileLength(remotePath);

// append header for part7.txt to summary.txt from memory
MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(header));
sftp.PutFile(ms, remotePath,
    remoteFileLength,  // remote offset
    ms.Length);  // number of bytes to upload

// update remote length
remoteFileLength += ms.Length;

// append data from part7.txt to summary.txt
sftp.PutFile(localPath, remotePath,
    0,  // local offset
    remoteFileLength,  // remote offset
    localFileLength);  // number of bytes to upload

VisualBasic

Dim localPath = "C:\MyData\part7.txt"
Dim remotePath = "/MyData/summary.txt"
Dim header = String.Format("<FILE>: {0}" & vbLf, localPath)
Dim localFileLength = New FileInfo(localPath).Length
Dim remoteFileLength = sftp.GetFileLength(remotePath)

' append header for part7.txt to summary.txt from memory
Dim ms = New MemoryStream(Encoding.UTF8.GetBytes(header))
sftp.PutFile(ms, remotePath,
    remoteFileLength, ms.Length)
'   remote offset, number of bytes to upload

' update remote length
remoteFileLength += ms.Length

' append data from part7.txt to summary.txt
sftp.PutFile(localPath, remotePath,
    0, remoteFileLength, localFileLength)
'   local offset, remote offset, number of bytes to upload

Partial file transfer (resuming) #

If you need to simply resume a failed file transfer, use Upload and Download methods.

But if you prefer to have more control over the process, partial file transfer support in GetFile and PutFile methods might be useful. To resume a file transfer, determine the length of the local file and the length of the remote file. Then transfer the missing part.

Resuming upload:

CSharp

string localPath = @"C:\MyData\file.txt";
string remotePath = "/MyData/file.txt";
long localFileLength = new FileInfo(localPath).Length;
long remoteFileLength = sftp.GetFileLength(remotePath);
long remains;

// resume failed upload
remains = localFileLength - remoteFileLength;
if (remains > 0)
{
    sftp.PutFile(localPath, remotePath,
        remoteFileLength,  // local offset
        remoteFileLength,  // remote offset
        remains);  // number of bytes to upload
}

VisualBasic

Dim localPath = "C:\MyData\file.txt"
Dim remotePath = "/MyData/file.txt"
Dim localFileLength = New FileInfo(localPath).Length
Dim remoteFileLength = sftp.GetFileLength(remotePath)
Dim remains As Long

' resume failed upload
remains = localFileLength - remoteFileLength
If remains > 0 Then
    sftp.PutFile(localPath, remotePath,
        remoteFileLength, remoteFileLength, remains)
    '   local offset, remote offset, number of bytes to upload
End If

Resuming download:

CSharp

string localPath = @"C:\MyData\file.txt";
string remotePath = "/MyData/file.txt";
long localFileLength = new FileInfo(localPath).Length;
long remoteFileLength = sftp.GetFileLength(remotePath);
long remains;

// resume failed download
remains = remoteFileLength - localFileLength;
if (remains > 0)
{
    sftp.GetFile(remotePath, localPath,
        localFileLength,  // remote offset
        localFileLength,  // local offset
        remains);  // number of bytes to download
}

VisualBasic

Dim localPath = "C:\MyData\file.txt"
Dim remotePath = "/MyData/file.txt"
Dim localFileLength = New FileInfo(localPath).Length
Dim remoteFileLength = sftp.GetFileLength(remotePath)
Dim remains As Long

' resume failed download
remains = remoteFileLength - localFileLength
If remains > 0 Then
    sftp.GetFile(remotePath, localPath,
        localFileLength, localFileLength, remains)
    '   remote offset, local offset, number of bytes to download
End If