使用C#和SSH.NET复制或移动远程文件

20

我知道使用SSH.NET库的SftpClient类可以上传和下载文件到/从SFTP服务器,但我不确定如何使用这个类来复制或移动SFTP服务器上的远程文件。我在互联网上也没有找到相关资料。如何使用SSH.NET库和C#将远程文件从目录A复制或移动到目录B?

更新: 我还尝试使用下面的代码实验SshClient类,但它什么都没做,既没有错误也没有异常。

ConnectionInfo ConnNfo = new ConnectionInfo("FTPHost", 22, "FTPUser",
new AuthenticationMethod[]{

   // Pasword based Authentication
   new PasswordAuthenticationMethod("FTPUser","FTPPass")
   }                
   );

using (var ssh = new SshClient(ConnNfo))
{
    ssh.Connect();                
    if (ssh.IsConnected)
    {                    
         string comm = "pwd";
         using (var cmd = ssh.CreateCommand(comm))
         {
            var returned = cmd.Execute();
            var output = cmd.Result;
            var err = cmd.Error;
            var stat = cmd.ExitStatus;
         }
     }
   ssh.Disconnect();
}

在Visual Studio控制台上,我获得以下输出。

*SshNet.Logging详细:1:向服务器发送消息“ChannelRequestMessage”:'SSH_MSG_CHANNEL_REQUEST:#152199'。

SshNet.Logging详细:1:从服务器接收消息:“ChannelFailureMessage”:'SSH_MSG_CHANNEL_FAILURE:#0'。*


你能在命令提示符中telnet到FTP服务器吗? - Hatjhie
我可以成功地使用WinSCP工具连接并复制粘贴文件。除此之外,我还可以成功地使用SSH.NET库的“SftpClient”类连接并下载文件。 - user1451111
你使用RunCommand而不是CreateCommand怎么样? - Hatjhie
这个链接可能有用:https://dev59.com/lWgu5IYBdhLWcg3wrIqR - Hatjhie
3个回答

22

使用Renci的NuGet包SSH.NET,我使用以下代码:

using Renci.SshNet;
using Renci.SshNet.SftpClient;    

...

        SftpClient _sftp = new SftpClient(_host, _username, _password);

移动文件:

        var inFile = _sftp.Get(inPath);
        inFile.MoveTo(outPath);

复制文件:

       var fsIn = _sftp.OpenRead(inPath);
       var fsOut = _sftp.OpenWrite(outPath);

        int data;
        while ((data = fsIn.ReadByte()) != -1)
            fsOut.WriteByte((byte)data);

        fsOut.Flush();
        fsIn.Close();
        fsOut.Close();

1
这绝对是最简单和最好的解决方案,也是唯一对我有效的解决方案。 - Kevin
你没有清空 fsIn 的原因是什么? - Barry O'Kane
我认为 fsOut.Flush() 实际上强制执行了 fsIn.Flush(),但不确定百分之百。 - Brian Rice
请注意,MoveTo将把所有文件移动到新目录。 - Abdullah Tahan
我认为应该使用Open(outPath, FileMode.Create, FileAccess.Write);而不是OpenWrite(outPath)。因为OpenWrite不会覆盖文件。https://github.com/sshnet/SSH.NET/blob/ab2ccc40bce835ce1d3c136aa702459bfd9948b7/src/Renci.SshNet/SftpClient.cs#L1581 - Glebka
创建(outPath) - Glebka

20

除了SSH.NET的SftpClient外,还有更简单的ScpClient。当我遇到SftpClient问题时,ScpClient能够正常工作。 ScpClient只具有上传/下载功能,但这已经满足了我的使用情况。

上传:

using (ScpClient client = new ScpClient(host, username, password))
{
    client.Connect();

    using (Stream localFile = File.OpenRead(localFilePath))
    {
         client.Upload(localFile, remoteFilePath);
    }
}

下载中:

using (ScpClient client = new ScpClient(host, username, password))
{
    client.Connect();

    using (Stream localFile = File.Create(localFilePath))
    {
         client.Download(remoteFilePath, localFile);
    }
}

1
可以正常工作。确保在项目中包含SSH.NET。我使用了Nuget包管理器。 - Umar Dastgir
上传进度有没有相关的信息可以获取? - s4eed

16

使用SSH.NET库可以移动远程文件。该库可以在此处找到:https://github.com/sshnet/SSH.NET

以下是将源文件夹中的第一个文件移动到另一个文件夹的示例代码。根据FTP设置,在类中设置私有变量。

using System;
using System.Linq;
using System.Collections.Generic;
using Renci.SshNet;
using Renci.SshNet.Sftp;
using System.IO;
using System.Configuration;
using System.IO.Compression;

public class RemoteFileOperations
{
    private string ftpPathSrcFolder = "/Path/Source/";//path should end with /
    private string ftpPathDestFolder = "/Path/Archive/";//path should end with /
    private string ftpServerIP = "Target IP";
    private int ftpPortNumber = 80;//change to appropriate port number
    private string ftpUserID = "FTP USer Name";//
    private string ftpPassword = "FTP Password";
    /// <summary>
    /// Move first file from one source folder to another. 
    /// Note: Modify code and add a for loop to move all files of the folder
    /// </summary>
    public void MoveFolderToArchive()
    {
        using (SftpClient sftp = new SftpClient(ftpServerIP, ftpPortNumber, ftpUserID, ftpPassword))
        {
            SftpFile eachRemoteFile = sftp.ListDirectory(ftpPathSrcFolder).First();//Get first file in the Directory            
            if(eachRemoteFile.IsRegularFile)//Move only file
            {
                bool eachFileExistsInArchive = CheckIfRemoteFileExists(sftp, ftpPathDestFolder, eachRemoteFile.Name);

                //MoveTo will result in error if filename alredy exists in the target folder. Prevent that error by cheking if File name exists
                string eachFileNameInArchive = eachRemoteFile.Name;

                if (eachFileExistsInArchive)
                {
                    eachFileNameInArchive = eachFileNameInArchive + "_" + DateTime.Now.ToString("MMddyyyy_HHmmss");//Change file name if the file already exists
                }
                eachRemoteFile.MoveTo(ftpPathDestFolder + eachFileNameInArchive);
            }           
        }
    }

    /// <summary>
    /// Checks if Remote folder contains the given file name
    /// </summary>
    public bool CheckIfRemoteFileExists(SftpClient sftpClient, string remoteFolderName, string remotefileName)
    {
        bool isFileExists = sftpClient
                            .ListDirectory(remoteFolderName)
                            .Any(
                                    f => f.IsRegularFile &&
                                    f.Name.ToLower() == remotefileName.ToLower()
                                );
        return isFileExists;
    }

}

感谢您提醒在移动文件之前检查文件是否已经存在。我一直遇到一个常规的“失败”错误,但实际上是由于这个问题导致的。 - Pine Code

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接