Linger.FileSystem.Ftp
1.3.3-preview
See the version list below for details.
dotnet add package Linger.FileSystem.Ftp --version 1.3.3-preview
NuGet\Install-Package Linger.FileSystem.Ftp -Version 1.3.3-preview
<PackageReference Include="Linger.FileSystem.Ftp" Version="1.3.3-preview" />
<PackageVersion Include="Linger.FileSystem.Ftp" Version="1.3.3-preview" />
<PackageReference Include="Linger.FileSystem.Ftp" />
paket add Linger.FileSystem.Ftp --version 1.3.3-preview
#r "nuget: Linger.FileSystem.Ftp, 1.3.3-preview"
#:package Linger.FileSystem.Ftp@1.3.3-preview
#addin nuget:?package=Linger.FileSystem.Ftp&version=1.3.3-preview&prerelease
#tool nuget:?package=Linger.FileSystem.Ftp&version=1.3.3-preview&prerelease
Linger.FileSystem.Ftp
Overview
Linger.FileSystem.Ftp is an implementation of the Linger FileSystem abstraction that provides FTP file operations support. It uses the FluentFTP library to offer a robust and retry-capable FTP client for common file operations such as uploading, downloading, listing, and deleting files.
Installation
dotnet add package Linger.FileSystem.Ftp
Features
- File operations over FTP (upload, download, list, delete)
- Configurable retry policies for unstable networks
- Timeout configurations
- Seamless integration with other Linger.FileSystem components
- Supports multiple .NET frameworks (net9.0, net8.0, netstandard2.0)
Basic Usage
Creating an FTP File System Instance
// Create settings for remote FTP system
var settings = new RemoteSystemSetting
{
Host = "ftp.example.com",
Port = 21,
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 FTP file system
using var ftpSystem = new FtpFileSystem(settings, retryOptions);
// Connect to the server
await ftpSystem.ConnectAsync();
// Upload a file
await using var stream = File.OpenRead("./local/file.txt");
var result = await ftpSystem.UploadAsync(stream, "/remote/path/file.txt", overwrite: true);
if (result.Success)
{
Console.WriteLine($"Upload successful: {result.FilePath}");
}
// Download a file
var downloadResult = await ftpSystem.DownloadFileAsync("/remote/path/file.txt", "C:/Downloads/file.txt");
if (downloadResult.Success)
{
Console.WriteLine($"Downloaded {downloadResult.FileSize} bytes");
}
// Disconnect when done
await ftpSystem.DisconnectAsync();
File Upload Methods
// Method 1: Upload from stream to complete file path
await using var stream = File.OpenRead("local.txt");
var result = await ftpSystem.UploadAsync(stream, "/remote/path/file.txt", overwrite: true);
// Method 2: Upload local file to complete remote path
result = await ftpSystem.UploadFileAsync("C:/local/file.txt", "/remote/path/file.txt", overwrite: true);
// Method 3: Upload with separate directory and filename (convenient for dynamic naming)
result = await ftpSystem.UploadFileAsync(
"C:/local/file.txt", // Local file path
"/remote/directory", // Remote directory
"custom-name.txt", // Custom filename
overwrite: true
);
Integration with Dependency Injection
// In your startup class
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IFileSystemOperations>(provider => {
var settings = new RemoteSystemSetting
{
Host = "ftp.example.com",
Port = 21,
UserName = "username",
Password = "password",
ConnectionTimeout = 15000,
OperationTimeout = 60000
};
var retryOptions = new RetryOptions
{
MaxRetryAttempts = 3,
DelayMilliseconds = 1000,
MaxDelayMilliseconds = 5000
};
return new FtpFileSystem(settings, retryOptions);
});
}
Advanced Features
Working Directory Management
// Set working directory
await ftpSystem.SetWorkingDirectoryAsync("/public_html");
// Get current working directory
var currentDir = await ftpSystem.GetWorkingDirectoryAsync();
Console.WriteLine($"Current directory: {currentDir}");
Directory Listing and Manipulation
// List directory contents
var files = await ftpSystem.ListDirectoryAsync("/public_html");
foreach (var file in files)
{
Console.WriteLine($"File: {file.Name}, Size: {file.Size}, Modified: {file.Modified}");
}
// Create directory
await ftpSystem.CreateDirectoryAsync("/public_html/uploads");
// Check if directory exists
bool exists = await ftpSystem.DirectoryExistsAsync("/public_html/uploads");
Batch File Operations
// Batch upload to a remote directory
var localFiles = new[] { "C:/data/a.txt", "C:/data/b.txt", "C:/data/c.txt" };
var uploadResult = await ftpSystem.UploadFilesAsync(localFiles, "/remote/uploads", overwrite: true);
Console.WriteLine($"Uploaded: {uploadResult.SucceededFiles.Count}, Failed: {uploadResult.FailedFiles.Count}");
// Batch download into a local directory
var remoteFiles = new[] { "/remote/uploads/a.txt", "/remote/uploads/b.txt" };
var downloadResult = await ftpSystem.DownloadFilesAsync(remoteFiles, "C:/Downloads", overwrite: true);
Console.WriteLine($"Downloaded: {downloadResult.SucceededFiles.Count}, Failed: {downloadResult.FailedFiles.Count}");
// Batch delete
var deleteResult = await ftpSystem.DeleteFilesAsync(new[]
{
"/remote/uploads/a.txt",
"/remote/uploads/b.txt"
});
Console.WriteLine($"Deleted: {deleteResult.SucceededFiles.Count}, Failed: {deleteResult.FailedFiles.Count}");
Each batch call returns a BatchOperationResult containing SucceededFiles and FailedFiles with detailed error information.
Batch Operation Progress Reporting
You can monitor batch operation progress using the IProgress<BatchProgress> parameter:
// Create a progress handler
var progress = new Progress<BatchProgress>(p =>
{
Console.WriteLine($"Progress: {p.Completed}/{p.Total} ({p.PercentComplete:F1}%)");
Console.WriteLine($"Current file: {p.CurrentFile}");
Console.WriteLine($"Succeeded: {p.Succeeded}, Failed: {p.Failed}");
});
// Batch upload with progress reporting
var localFiles = new[] { "C:/data/a.txt", "C:/data/b.txt", "C:/data/c.txt" };
var result = await ftpSystem.UploadFilesAsync(localFiles, "/remote/uploads", overwrite: true, progress);
// Batch download with progress
var remoteFiles = new[] { "/remote/uploads/a.txt", "/remote/uploads/b.txt" };
var downloadResult = await ftpSystem.DownloadFilesAsync(remoteFiles, "C:/Downloads", overwrite: true, progress);
// Batch delete with progress
var deleteResult = await ftpSystem.DeleteFilesAsync(new[] { "/remote/old.txt" }, progress);
The BatchProgress struct provides:
Completed: Number of files processed (reported after each file completes)Total: Total number of filesCurrentFile: Path of the file that was just processedSucceeded: Number of successful operationsFailed: Number of failed operationsPercentComplete: Completion percentage (0-100)
Note: Progress is reported after each file operation completes, ensuring Completed always reflects the accurate count.
Custom Connection Settings
var settings = new RemoteSystemSetting
{
Host = "ftp.example.com",
Port = 21,
UserName = "username",
Password = "password",
ConnectionTimeout = 30000, // 30 seconds connection timeout
OperationTimeout = 120000, // 2 minutes operation timeout
Type = "FTP",
// Concurrency for batch operations: 1 = serial, >1 = parallel
MaxDegreeOfParallelism = 4,
// Connection pool idle timeout (optional)
// Connections idle longer than this will be discarded and recreated
ConnectionPoolIdleTimeout = TimeSpan.FromMinutes(5),
// Batch operation retry settings
BatchRetryOptions = new RetryOptions
{
MaxRetryAttempts = 3,
DelayMilliseconds = 1000
}
};
// Advanced retry configuration
var retryOptions = new RetryOptions
{
MaxRetryAttempts = 5,
DelayMilliseconds = 2000,
MaxDelayMilliseconds = 30000,
UseExponentialBackoff = true // Use exponential backoff for retries
};
var ftpSystem = new FtpFileSystem(settings, retryOptions);
### Concurrency for Batch Operations
You can control parallelism for batch upload/download/delete via `RemoteSystemSetting.MaxDegreeOfParallelism`.
Behavior:
- `MaxDegreeOfParallelism = 1`: single connection, serial execution.
- `MaxDegreeOfParallelism > 1`: per-task independent `AsyncFtpClient` connections for thread safety and throughput.
Example:
```csharp
var settings = new RemoteSystemSetting
{
Host = "ftp.example.com",
Port = 21,
UserName = "username",
Password = "password",
ConnectionTimeout = 15000,
OperationTimeout = 60000,
MaxDegreeOfParallelism = 4
};
var ftp = new FtpFileSystem(settings);
await ftp.ConnectAsync();
var files = new[] { "C:/data/a.txt", "C:/data/b.txt", "C:/data/c.txt" };
var result = await ftp.UploadFilesAsync(files, "/remote/uploads", overwrite: true);
Console.WriteLine($"Uploaded: {result.SucceededFiles.Count}, Failed: {result.FailedFiles.Count}");
### File Information and Metadata
```csharp
// Get file size
long fileSize = await ftpSystem.GetFileSizeAsync("/remote/file.txt");
// Get file last modified time
DateTime modTime = await ftpSystem.GetModifiedTimeAsync("/remote/file.txt");
// Check if file exists
bool exists = await ftpSystem.FileExistsAsync("/remote/file.txt");
Connection Management Best Practices
// Method 1: Automatic connection management with using statement
using (var ftpSystem = new FtpFileSystem(settings))
{
// Connection is automatically established and closed
await ftpSystem.UploadFileAsync("local.txt", "/remote/path");
await ftpSystem.DownloadFileAsync("/remote/file.txt", "downloaded.txt");
}
// Method 2: Manual connection management for multiple operations
var ftpSystem = new FtpFileSystem(settings);
try
{
await ftpSystem.ConnectAsync();
// Perform multiple operations efficiently
for (int i = 0; i < 10; i++)
{
await ftpSystem.UploadFileAsync($"file{i}.txt", $"/remote/file{i}.txt");
}
}
finally
{
await ftpSystem.DisconnectAsync();
}
Error Handling and Troubleshooting
Common FTP Exceptions
try
{
await ftpSystem.UploadFileAsync("local.txt", "/remote/path");
}
catch (FileSystemException ex)
{
switch (ex.Operation)
{
case "Upload":
Console.WriteLine($"Upload failed: {ex.Message}");
break;
case "Connect":
Console.WriteLine($"Connection failed: {ex.Message}");
break;
}
}
catch (TimeoutException ex)
{
Console.WriteLine($"Operation timed out: {ex.Message}");
}
Retry Configuration for Unstable Networks
var retryOptions = new RetryOptions
{
MaxRetryAttempts = 10, // Retry up to 10 times
DelayMilliseconds = 1000, // Start with 1 second delay
MaxDelayMilliseconds = 60000, // Maximum 60 seconds delay
UseExponentialBackoff = true // Increase delay exponentially
};
var ftpSystem = new FtpFileSystem(settings, retryOptions);
Dependencies
- FluentFTP: Modern FTP client library
- Linger.FileSystem: Core abstraction library
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
- FluentFTP (>= 54.1.1)
- Linger.FileSystem (>= 1.3.3-preview)
-
net10.0
- FluentFTP (>= 54.1.1)
- Linger.FileSystem (>= 1.3.3-preview)
-
net8.0
- FluentFTP (>= 54.1.1)
- Linger.FileSystem (>= 1.3.3-preview)
-
net9.0
- FluentFTP (>= 54.1.1)
- Linger.FileSystem (>= 1.3.3-preview)
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 |
|---|---|---|
| 1.4.1-preview | 43 | 5/12/2026 |
| 1.4.0 | 67 | 5/6/2026 |
| 1.3.3-preview | 80 | 5/5/2026 |
| 1.3.2-preview | 91 | 4/29/2026 |
| 1.3.1-preview | 91 | 4/28/2026 |
| 1.3.0-preview | 88 | 4/27/2026 |
| 1.2.0-preview | 103 | 3/29/2026 |
| 1.1.0 | 121 | 2/4/2026 |
| 1.0.3-preview | 117 | 1/9/2026 |
| 1.0.2-preview | 113 | 1/8/2026 |
| 1.0.0 | 313 | 11/12/2025 |
| 1.0.0-preview2 | 217 | 11/6/2025 |
| 1.0.0-preview1 | 217 | 11/5/2025 |
| 0.9.9 | 211 | 10/16/2025 |
| 0.9.8 | 200 | 10/14/2025 |
| 0.9.7-preview | 190 | 10/13/2025 |
| 0.9.6-preview | 182 | 10/12/2025 |
| 0.9.5 | 184 | 9/28/2025 |
| 0.9.4-preview | 213 | 9/25/2025 |
| 0.9.3-preview | 233 | 9/22/2025 |