Our Products:   CompleteFTP  edtFTPnet/Free  edtFTPnet/PRO  edtFTPj/Free  edtFTPj/PRO
–1 vote
135 views
in .NET FTP by (51.2k points)
I'd like to download and upload files concurrently, controlling the speed, by chunking the transfers and delaying after each chunk as required.

1 Answer

0 votes
by (51.2k points)
 
Best answer

SecureFTPConnection actually has a MaxTransferRate property that you can use to control the speed, but if you'd like to control the size of the chunks as well, then you can do it as follows:

var conn = new SecureFTPConnection
{
    ServerAddress = serverAddress,
    UserName = userName,
    Password = password,
    Protocol = FileTransferProtocol.SFTP
};
conn.ConcurrentTransferSettings.Enabled = true;
conn.CloseStreamsAfterTransfer = true;

try
{
    conn.Connect();

    var downloadTask = Task.Factory.FromAsync(
        conn.BeginDownloadStream(new ThrottledStream(File.Create(localDownloadFile), 1024 * 1024, 1000), remoteDownloadFile, null, null),
        ar => conn.EndDownloadStream(ar)
    );
    var uploadTask = Task.Factory.FromAsync(
        conn.BeginUploadStream(new ThrottledStream(File.OpenRead(localUploadFile), 1024 * 1024, 1000), remoteUploadFile, null, null),
        ar => conn.EndUploadStream(ar)
    );

    await Task.WhenAll(downloadTask, uploadTask);
}
finally
{
    conn.Close();
}

where ThrottledStream is:

public class ThrottledStream : Stream
{
    private Stream _baseStream;
    private long _bytesPerPause;
    private int _pauseDuration;
    private long _bytesRead;
    private long _bytesWritten;

    public ThrottledStream(Stream baseStream, long bytesPerPause, int pauseDuration)
    {
        _baseStream = baseStream;
        _bytesPerPause = bytesPerPause;
        _pauseDuration = pauseDuration;
        _bytesRead = 0;
        _bytesWritten = 0;
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        _baseStream.Write(buffer, offset, count);
        _bytesWritten += count;

        if (_bytesWritten >= _bytesPerPause)
        {
            System.Threading.Thread.Sleep(_pauseDuration);
            _bytesWritten = 0;
        }
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        int bytesRead = _baseStream.Read(buffer, offset, count);
        _bytesRead += bytesRead;

        if (_bytesRead >= _bytesPerPause)
        {
            System.Threading.Thread.Sleep(_pauseDuration);
            _bytesRead = 0;
        }

        return bytesRead;
    }

    // Other Stream methods should delegate to the _baseStream
    public override bool CanRead => _baseStream.CanRead;
    public override bool CanSeek => _baseStream.CanSeek;
    public override bool CanWrite => _baseStream.CanWrite;
    public override long Length => _baseStream.Length;

    public override long Position
    {
        get { return _baseStream.Position; }
        set { _baseStream.Position = value; }
    }

    public override void Flush() => _baseStream.Flush();
    public override long Seek(long offset, SeekOrigin origin) => _baseStream.Seek(offset, origin);
    public override void SetLength(long value) => _baseStream.SetLength(value);

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            _baseStream.Dispose();
        }

        base.Dispose(disposing);
    }
}

Categories

...