3

We currently are using WinSCP .NET assembly to interact with SFTP servers. Our use case involves fetching parts of a file in chunks. I see that TransferResumeSupportState transfer option can be used to resume the file download but does not give freedom to stop and start/resume download as and when needed.

One of the other use case does not require the part of the file already downloaded (processed) to be in the same location (part of file downloaded is processed and not needed anymore). For TransferResumeSupportState option to work the part of the file already downloaded has to be present in the same location.

Is there a workaround to pass file offset value to the GetFiles?

Thanks,
Vagore

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
Varun Gore
  • 31
  • 4

2 Answers2

3

As an alternative, I would use SSH.NET for this task where you can operate directly on streams.

var client = new SftpClient(connectionInfo);

client.Connect();

var sftpFileStream = client.OpenRead(filePath);

sftpFileStream.Seek(previouslyReadOffset, SeekOrigin.Begin);
sftpFileStream.CopyTo(localStream);
Andrii Litvinov
  • 12,402
  • 3
  • 52
  • 59
1

This is not possible with WinSCP .NET assembly.

All you can do is to cheat WinSCP by

  • creating a dummy local file with the size you want to skip and
  • setting the TransferOptions.OverwriteMode to the OverwriteMode.Resume (note that it's not about the TransferResumeSupportState) and passing the created TransferOptions to the Session.GetFiles:
long offset = 1024 * 1024;
const string remotePath = "/remote/path";

// Quickly create an dummy temporary local file with the desired size
string localPath = Path.GetTempFileName();
using (FileStream fs = File.Create(localPath))
{
    fs.SetLength(offset);
}

// "Resume" the download
TransferOptions transferOptions = new TransferOptions();
transferOptions.OverwriteMode = OverwriteMode.Resume;
session.GetFiles(
    RemotePath.EscapeFileMask(remotePath), localPath, false, transferOptions).Check();

// Read the downloaded chunk 
byte[] chunk;
using (FileStream fs = File.OpenRead(localPath))
{
    fs.Seek(offset, SeekOrigin.Begin);

    int downloaded = (int)(fs.Length - offset);
    chunk = new byte[downloaded];
    fs.Read(chunk, 0, downloaded);
}

// Delete the temporary file
File.Delete(localPath);

The SetLength trick is based on Creating a Huge Dummy File in a Matter of Seconds in C#.

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992