c# - 使用 WinSCP Session.GetFile 从 SFTP 进行流式传输失败 – ((WinSCP.PipeStream)stream).Length' 引发类型 'System.NotSupportedException' 的异常

标签 c# .net azure sftp winscp

我的应用程序需要使用 SFTP 将文件从某个位置直接复制到 Azure 存储。 我们的应用程序使用 C# 和 .NET 4.6,我们的 WinSCP 版本是 5.21.1。

我的旧代码使用 Session.GetFileToDirectory() 方法工作,但问题是它需要将文件存储在我们托管内的临时文件夹中。

using (Session session = new Session())
{
    session.Open(sessionOptions);

    TransferOptions transferOptions = new TransferOptions();
    transferOptions.TransferMode = TransferMode.Binary;

    var transfer = session.GetFileToDirectory(FilePath, fullPath);
    using (Stream stream = File.OpenRead(transfer.Destination))
    {  
        UploadToAzure(stream, Filename, Foldername); 
    }
}

由于我们计划完全使用 Azure 存储,因此我像这样更改了代码

using (Session session = new Session())
{
    session.Open(sessionOptions);
    TransferOptions transferOptions = new TransferOptions();
    transferOptions.TransferMode = TransferMode.Binary;

    using (Stream stream = session.GetFile(FilePath, transferOptions))
    {
        UploadToAzure(stream, Filename, Foldername);   
    }
}

这是我的库,它使用 Stream 将文件上传到 Azure。 此代码使用我的旧代码运行良好,在发送到 Azure 之前仍然保存到临时文件夹。

public static string UploadToAzure(Stream attachment, string Filename, string Foldername)
{
    System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;

    var connectionString = $"{ConfigurationManager.AppSettings["AzureFileShareConnectionString"]}";
    string shareName = $"{ConfigurationManager.AppSettings["AzureFileShareFolderName"]}";
    string dirName = $"files\\{Foldername}";
    string fileName = Filename;

    try
    {  
        ShareClient share = new ShareClient(connectionString, shareName);
        share.CreateIfNotExists();
                 
        ShareDirectoryClient directory = share.GetDirectoryClient(dirName);
        directory.CreateIfNotExists();

        // Get a reference to a file and upload it
        ShareFileClient file = directory.GetFileClient(fileName);

        file.Create(attachment.Length);
        file.UploadRange(
            new HttpRange(0, attachment.Length), attachment);

    }
    catch (Exception e)
    {
        return $"Uploaded {Filename} failed : {e.ToString()}";
    }

    return $"{Filename} Uploaded";
}

但目前我的新代码无法处理错误消息

'((WinSCP.PipeStream)stream).Length' threw an exception of type 'System.NotSupportedException'.

这是使用Session.GetFile方法创建流的对象描述 enter image description here

这是将空流发送到 Azure 时的“异常堆栈跟踪” enter image description here

最佳答案

The Stream returned by WinSCP Session.GetFile不实现Stream.Length属性,因为WinSCP不能保证文件的大小是固定的。下载文件时,远程文件可能正在更改。更不用说ASCII传输模式,当文件在传输的同时进行转换,对最终的大小产生不可预测的影响。

您在两个地方使用大小 (Stream.Length):

  • 创建文件时:

    file.Create(attachment.Length);
    

    ShareFileClient.Create的参数是maxSize。所以它看起来不像是真实尺寸。您可以在此处输入任意大的数字。

    或者,如果您愿意(并且知道文件没有更改),可以使用 Session.GetFileInfo 读取远程文件的当前大小。和 RemoteFileInfo.Length :

    file.Create(session.GetFileInfo(FilePath).Length);
    
  • 上传内容时:

    file.UploadRange(new HttpRange(0, attachment.Length), attachment);
    

    上面可以用简单的ShareFileClient.Upload来代替:

    file.Upload(attachment);
    

关于c# - 使用 WinSCP Session.GetFile 从 SFTP 进行流式传输失败 – ((WinSCP.PipeStream)stream).Length' 引发类型 'System.NotSupportedException' 的异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72809471/

相关文章:

c# - 尝试使用 VB6 Form 调用 OLEDB 提供程序时应用程序消失

c# - Entity Framework 根据输入参数动态查询表名

C# 导入多个 txt 文件数据变得困惑

c# - 备份和恢复mysql数据库c#

c# - Entity Framework 两个查询结果相同,但一个更快

azure - 如何使用 Terraform 创建服务主体并在提供程序中使用该主体?

c# - 从存储帐户 blob 读取和解析 Azure IoT 中心遥测

ios - Azure 通知中心 - 如何在同一中心设置多个应用程序

c# - 如何在 C# 中获取对象的小写名称,即使为 null

c# - C# 中的 antlr4 parser.prog