Linger.FileSystem.Sftp
2.0.0-preview.1
dotnet add package Linger.FileSystem.Sftp --version 2.0.0-preview.1
NuGet\Install-Package Linger.FileSystem.Sftp -Version 2.0.0-preview.1
<PackageReference Include="Linger.FileSystem.Sftp" Version="2.0.0-preview.1" />
<PackageVersion Include="Linger.FileSystem.Sftp" Version="2.0.0-preview.1" />
<PackageReference Include="Linger.FileSystem.Sftp" />
paket add Linger.FileSystem.Sftp --version 2.0.0-preview.1
#r "nuget: Linger.FileSystem.Sftp, 2.0.0-preview.1"
#:package Linger.FileSystem.Sftp@2.0.0-preview.1
#addin nuget:?package=Linger.FileSystem.Sftp&version=2.0.0-preview.1&prerelease
#tool nuget:?package=Linger.FileSystem.Sftp&version=2.0.0-preview.1&prerelease
Linger.FileSystem.Sftp
Breaking changes and 2.0 migration notes are documented in the Linger migration guide.
Overview
Linger.FileSystem.Sftp is an implementation of the Linger FileSystem abstraction that provides SFTP (SSH File Transfer Protocol) file operations support. It utilizes the SSH.NET library to offer a secure and reliable SFTP client for file operations with support for both password and certificate-based authentication.
Installation
dotnet add package Linger.FileSystem.Sftp
Features
- Secure file operations over SFTP (upload, download, list, delete)
- Support for both password and certificate-based authentication
- Configurable retry policies for unstable networks
- Timeout configurations
- Integration with the Linger.FileSystem abstraction
- Supports multiple .NET frameworks (net9.0, net8.0, netstandard2.0)
Basic Usage
Creating an SFTP File System Instance with Password Authentication
// Create settings for remote SFTP system with password authentication
var settings = new SftpFileSystemOptions
{
Host = "sftp.example.com",
Port = 22,
UserName = "username",
Password = "password",
ConnectionTimeout = 15000, // 15 seconds
OperationTimeout = 60000 // 60 seconds
};
// Configure retry options
var retryOptions = new RetryOptions
{
MaxRetryAttempts = 3,
DelayMilliseconds = 1000,
MaxDelayMilliseconds = 5000
};
// Create SFTP file system
using var sftpSystem = new SftpFileSystem(settings, retryOptions);
// Upload a file
await using var stream = File.OpenRead("./local/file.txt");
var result = await sftpSystem.UploadAsync(stream, "/remote/path/file.txt", overwrite: true);
if (result.Success)
{
Console.WriteLine($"Upload successful: {result.FilePath}");
}
// Download a file
var downloadResult = await sftpSystem.DownloadFileAsync("/remote/path/file.txt", "C:/Downloads/file.txt");
if (downloadResult.Success)
{
var downloadedBytes = await sftpSystem.GetFileSizeAsync("/remote/path/file.txt");
Console.WriteLine($"Downloaded {downloadedBytes} bytes");
}
File Upload Methods
// Method 1: Upload from stream to complete file path
await using var stream = File.OpenRead("local.txt");
var result = await sftpSystem.UploadAsync(stream, "/remote/path/file.txt", overwrite: true);
// Method 2: Upload local file to complete remote path
result = await sftpSystem.UploadFileAsync("C:/local/file.txt", "/remote/path/file.txt", overwrite: true);
Using Certificate-based Authentication
// Create settings for remote SFTP system with certificate authentication
var settings = new SftpFileSystemOptions
{
Host = "sftp.example.com",
Port = 22,
UserName = "username",
CertificatePath = "/path/to/private/key.pem",
CertificatePassphrase = "optional-passphrase", // If the private key is protected with a passphrase
ConnectionTimeout = 15000, // 15 seconds
OperationTimeout = 60000 // 60 seconds
};
// Create SFTP file system with certificate authentication
using var sftpSystem = new SftpFileSystem(settings);
// The first operation connects automatically
await sftpSystem.FileExistsAsync("/remote/path/file.txt");
Asynchronous Operations
The library also provides asynchronous methods for all operations:
// Check if file exists asynchronously
if (await sftpSystem.FileExistsAsync("/remote/path/file.txt"))
{
// Download file asynchronously
var fileContent = await sftpSystem.ReadAllTextAsync("/remote/path/file.txt");
// Process file content
Console.WriteLine(fileContent);
}
Advanced Features
Working Directory Management
// Get current working directory
var currentDir = sftpSystem.GetCurrentDirectory();
Console.WriteLine($"Current directory: {currentDir}");
// Change working directory
sftpSystem.ChangeDirectory("/home/user/documents");
// Get directory listing with details
var files = sftpSystem.GetFiles("/remote/path", "*", SearchOption.TopDirectoryOnly);
foreach (var file in files)
{
Console.WriteLine($"File: {file}");
}
// Get directories
var directories = sftpSystem.GetDirectories("/remote/path");
foreach (var dir in directories)
{
Console.WriteLine($"Directory: {dir}");
}
Custom Connection Settings
// Advanced SFTP settings with custom configurations
var settings = new SftpFileSystemOptions
{
Host = "sftp.example.com",
Port = 2222, // Custom port
UserName = "username",
Password = "password",
// Connection settings
ConnectionTimeout = 30000, // 30 seconds
OperationTimeout = 120000 // 2 minutes
};
// Enhanced retry configuration
var retryOptions = new RetryOptions
{
MaxRetryAttempts = 5,
DelayMilliseconds = 2000,
MaxDelayMilliseconds = 10000,
UseExponentialBackoff = true // Exponential backoff
};
using var sftpSystem = new SftpFileSystem(settings, retryOptions);
Error Handling and Connection Lifetime
using var sftpSystem = new SftpFileSystem(settings, retryOptions);
try
{
// Perform operations with automatic retry
if (await sftpSystem.FileExistsAsync("/remote/important-file.txt"))
{
var content = await sftpSystem.ReadAllTextAsync("/remote/important-file.txt");
// Process content safely
if (!string.IsNullOrEmpty(content))
{
// Save backup
await sftpSystem.WriteAllTextAsync("/remote/backup/important-file.bak", content);
}
}
}
catch (SftpException ex)
{
Console.WriteLine($"SFTP Error: {ex.Message}");
// Handle SFTP-specific errors
}
catch (SshException ex)
{
Console.WriteLine($"SSH Error: {ex.Message}");
// Handle SSH connection errors
}
File Permissions and Attributes
// Check file attributes
var fileInfo = sftpSystem.GetFileInfo("/remote/path/file.txt");
Console.WriteLine($"File size: {fileInfo.Length} bytes");
Console.WriteLine($"Last modified: {fileInfo.LastWriteTime}");
// Create directory with specific permissions (Unix-like systems)
sftpSystem.CreateDirectory("/remote/path/new-directory");
// Note: File permissions are typically handled at the SSH server level
// Check if file is readable/writable
if (sftpSystem.FileExists("/remote/path/file.txt"))
{
try
{
var testContent = sftpSystem.ReadAllText("/remote/path/file.txt");
Console.WriteLine("File is readable");
}
catch (UnauthorizedAccessException)
{
Console.WriteLine("File is not readable");
}
}
Streaming Operations for Large Files
// Stream large file download
using var remoteStream = sftpSystem.OpenRead("/remote/large-file.zip");
using var localStream = File.Create(@"C:\local\large-file.zip");
var buffer = new byte[8192]; // 8KB buffer
int bytesRead;
long totalBytes = 0;
while ((bytesRead = await remoteStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
{
await localStream.WriteAsync(buffer, 0, bytesRead);
totalBytes += bytesRead;
// Report progress
Console.WriteLine($"Downloaded: {totalBytes:N0} bytes");
}
Console.WriteLine($"Download completed: {totalBytes:N0} bytes total");
Configuration Examples
Production Configuration
var productionSettings = new SftpFileSystemOptions
{
Host = "prod-sftp.company.com",
Port = 22,
UserName = "prod-user",
CertificatePath = "/secure/certs/prod-key.pem",
ConnectionTimeout = 15000,
OperationTimeout = 300000 // 5 minutes for large files
};
var productionRetry = new RetryOptions
{
MaxRetryAttempts = 3,
DelayMilliseconds = 5000,
MaxDelayMilliseconds = 30000,
UseExponentialBackoff = true
};
Development Configuration
var devSettings = new SftpFileSystemOptions
{
Host = "dev-sftp.company.com",
Port = 22,
UserName = "dev-user",
Password = "dev-password",
ConnectionTimeout = 10000,
OperationTimeout = 60000
};
var devRetry = new RetryOptions
{
MaxRetryAttempts = 1,
DelayMilliseconds = 1000,
MaxDelayMilliseconds = 5000
};
Integration with Dependency Injection
// In your startup class
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IRemoteFileSystem>(provider => {
var settings = new SftpFileSystemOptions
{
Host = "sftp.example.com",
Port = 22,
UserName = "username",
Password = "password",
ConnectionTimeout = 15000,
OperationTimeout = 60000
};
var retryOptions = new RetryOptions
{
MaxRetryAttempts = 3,
DelayMilliseconds = 1000,
MaxDelayMilliseconds = 5000
};
return new SftpFileSystem(settings, retryOptions);
});
}
SftpFileSystem automatically connects on the first operation and keeps one client connection per instance. Do not
invoke operations concurrently on the same instance or mutate its working directory while another operation is running.
SSH.NET provides synchronous disposal only, so SFTP uses using and does not expose a pseudo-asynchronous DisposeAsync().
Best Practices
- Connection Management: Always use
usingstatements or ensure proper disposal of SFTP connections - Error Handling: Implement specific exception handling for
SftpExceptionandSshException - Authentication: Prefer certificate-based authentication over passwords for production environments
- Timeouts: Configure appropriate timeouts based on your network conditions and file sizes
- Retry Logic: Use exponential backoff for retry attempts to avoid overwhelming the server
- Large Files: Use streaming operations for files larger than available memory
- Security: Store connection credentials securely using configuration management or key vaults
Dependencies
License
This project is licensed under the terms of the license provided with the Linger project.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Linger.FileSystem (>= 2.0.0-preview.1)
- SSH.NET (>= 2026.0.0)
-
net10.0
- Linger.FileSystem (>= 2.0.0-preview.1)
- SSH.NET (>= 2026.0.0)
-
net8.0
- Linger.FileSystem (>= 2.0.0-preview.1)
- SSH.NET (>= 2026.0.0)
-
net9.0
- Linger.FileSystem (>= 2.0.0-preview.1)
- SSH.NET (>= 2026.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.0.0-preview.1 | 33 | 8/29/2026 |
| 1.6.4 | 111 | 8/16/2026 |
| 1.6.3 | 90 | 8/5/2026 |
| 1.6.2 | 105 | 8/2/2026 |
| 1.6.0 | 103 | 7/25/2026 |
| 1.5.5 | 101 | 7/23/2026 |
| 1.5.4-preview | 93 | 7/21/2026 |
| 1.5.3-preview | 90 | 7/20/2026 |
| 1.5.2-preview | 94 | 7/19/2026 |
| 1.5.1-preview | 93 | 7/15/2026 |
| 1.5.0-preview | 93 | 7/14/2026 |
| 1.4.4-preview | 105 | 6/16/2026 |
| 1.4.3-preview | 100 | 6/15/2026 |
| 1.4.2 | 118 | 5/20/2026 |
| 1.4.1-preview | 106 | 5/12/2026 |
| 1.4.0 | 108 | 5/6/2026 |
| 1.3.3-preview | 96 | 5/5/2026 |
| 1.3.2-preview | 112 | 4/29/2026 |
| 1.3.1-preview | 108 | 4/28/2026 |
| 1.3.0-preview | 104 | 4/27/2026 |