【问题标题】:Download all files and sub-directories from FTP folder in VB.NET从 VB.NET 中的 FTP 文件夹下载所有文件和子目录
【发布时间】:2017-09-22 11:34:36
【问题描述】:

我在整个互联网上搜索了我的问题,但我只找到了 C# 的答案,但没有找到 VB.NET 的答案。

我想下载我的 FTP 服务器上某个目录的所有文件和子目录。

我目前正在通过从我的 FTP 服务器下载一个 ZIP 文件并解压缩它,但这不是一个好方法。

谢谢!

【问题讨论】:

标签: .net vb.net ftp


【解决方案1】:

我知道您可能会懒惰地阅读所有内容,但这就是答案!!!代码在最后:D

你好,

使用可用于 C# 和 VB.NET 的 WinSCP 库非常简单 - 这是完整的答案:

首先,将 WinSCP 库安装到您的项目中,请参见此处:https://winscp.net/eng/docs/library#downloading_and_installing_the_assembly

或者,如果您懒得这样做,那么只需下载库并将 DLL 文件作为参考添加到您的项目中。

现在让我们将包括其文件及其子目录的整个目录下载到本地存储。

你有两个选择:

我当然使用了第二种选择,因为它是有史以来最好的选择。但是,如果您想使用 Session.GetFiles 方法...您可以在此处查看 VB.NET 示例:https://winscp.net/eng/docs/library_session_getfiles#vbnet

这是我使用第二个选项的方法:https://winscp.net/eng/docs/faq_script_modified_files

如您所见,一切都解释得很好!

基本上使用synchronize local 而不是getsynchronize remote 而不是put

对于 WinSCP .NET 程序集,这意味着,使用 Session.SynchronizeDirectories,参数模式设置为 SynchronizationMode.Remote 或 SynchronizationMode.Local 而不是 分别是 Session.GetFiles 或 Session.PutFiles。

因为我想将文件从 FTP 服务器下载到我的本地 PC,所以这是我使用的 (SynchronizeDirectories):

  1. 所以是的!当然是Imports WinSCP 首先:-)
  2. 使用此代码,因为https://winscp.net/eng/docs/library_session_synchronizedirectories#vbnet 上的代码用于 SFTP(端口 22)而不是 FTP(端口 21)...而且它还使用从您的 PC 上传到 FTP 服务器的SynchronizeMode.Remote,所以在下面的代码我用.Local替换了.Remote

    Public Shared Function Main() As Integer
    
        Try 
            ' Setup session options
            Dim sessionOptions As New SessionOptions
            With sessionOptions
                .Protocol = Protocol.Ftp
                .HostName = "example.com"
                .UserName = "user"
                .Password = "mypassword"
            End With
    
            Using session As New Session
                ' Will continuously report progress of synchronization
                AddHandler session.FileTransferred, AddressOf FileTransferred
    
                ' Connect
                session.Open(sessionOptions)
    
                ' Synchronize files
                Dim synchronizationResult As SynchronizationResult
                synchronizationResult = _
                    session.SynchronizeDirectories( _
                        SynchronizationMode.Local, "d:\www", "/home/martin/public_html", False)
    
                ' Throw on any error
                synchronizationResult.Check()
            End Using
    
            Return 0
        Catch e As Exception
            Console.WriteLine("Error: {0}", e)
            Return 1
        End Try
    
    End Function
    
    Private Shared Sub FileTransferred(ByVal sender As Object, ByVal e As TransferEventArgs)
    
        If e.Error Is Nothing Then
            'Console.WriteLine("Upload of {0} succeeded", e.FileName)
        Else
            'Console.WriteLine("Upload of {0} failed: {1}", e.FileName, e.Error)
        End If
    
        If e.Chmod IsNot Nothing Then
            If e.Chmod.Error Is Nothing Then
                'Console.WriteLine("Permisions of {0} set to {1}", e.Chmod.FileName, e.Chmod.FilePermissions)
            Else
                'Console.WriteLine("Setting permissions of {0} failed: {1}", e.Chmod.FileName, e.Chmod.Error)
            End If
        Else
            'Console.WriteLine("Permissions of {0} kept with their defaults", e.Destination)
        End If
    
        If e.Touch IsNot Nothing Then
            If e.Touch.Error Is Nothing Then
                'Console.WriteLine("Timestamp of {0} set to {1}", e.Touch.FileName, e.Touch.LastWriteTime)
            Else
                'Console.WriteLine("Setting timestamp of {0} failed: {1}", e.Touch.FileName, e.Touch.Error)
            End If
        Else
            ' This should never happen during "local to remote" synchronization
            'Console.WriteLine("Timestamp of {0} kept with its default (current time)", e.Destination)
        End If
    
    End Sub
    

不要忘记替换凭据和路径..

还有一件事?祝你的项目好运! :-)

【讨论】:

    【解决方案2】:

    将我对C# Download all files and subdirectories through FTP 的回答翻译成 VB.NET:

    FtpWebRequest 不明确支持递归文件操作(包括下载)。您必须自己实现递归:

    • 列出远程目录
    • 迭代条目、下载文件并递归到子目录(再次列出它们等)

    棘手的部分是从子目录中识别文件。 FtpWebRequest 无法以便携的方式做到这一点。 FtpWebRequest 不幸的是不支持 MLSD 命令,这是在 FTP 协议中检索具有文件属性的目录列表的唯一可移植方式。另见Checking if object on FTP server is file or directory

    您的选择是:

    • 对文件名执行操作,对于文件肯定会失败,而对于目录会成功(反之亦然)。 IE。您可以尝试下载“名称”。如果成功,它是一个文件,如果失败,它是一个目录。
    • 您可能很幸运,在您的特定情况下,您可以通过文件名来区分目录中的文件(即,您的所有文件都有扩展名,而子目录没有)
    • 您使用长目录列表(LIST 命令 = ListDirectoryDetails 方法)并尝试解析特定于服务器的列表。许多 FTP 服务器使用 *nix 样式的列表,您可以在其中通过条目开头的 d 标识目录。但是许多服务器使用不同的格式。以下示例使用这种方法(假设为 *nix 格式)
    Sub DownloadFtpDirectory(
            url As String, credentials As NetworkCredential, localPath As String)
        Dim listRequest As FtpWebRequest = WebRequest.Create(url)
        listRequest.Method = WebRequestMethods.Ftp.ListDirectoryDetails
        listRequest.Credentials = credentials
    
        Dim lines As List(Of String) = New List(Of String)
    
        Using listResponse As FtpWebResponse = listRequest.GetResponse(),
              listStream As Stream = listResponse.GetResponseStream(),
              listReader As StreamReader = New StreamReader(listStream)
            While Not listReader.EndOfStream
                lines.Add(listReader.ReadLine())
            End While
        End Using
    
        For Each line As String In lines
            Dim tokens As String() =
                line.Split(New Char() {" "}, 9, StringSplitOptions.RemoveEmptyEntries)
            Dim name As String = tokens(8)
            Dim permissions As String = tokens(0)
    
            Dim localFilePath As String = Path.Combine(localPath, name)
            Dim fileUrl As String = url + name
    
            If permissions(0) = "d" Then
                If Not Directory.Exists(localFilePath) Then
                    Directory.CreateDirectory(localFilePath)
                End If
                DownloadFtpDirectory(fileUrl + "/", credentials, localFilePath)
            Else
                Dim downloadRequest As FtpWebRequest = WebRequest.Create(fileUrl)
                downloadRequest.Method = WebRequestMethods.Ftp.DownloadFile
                downloadRequest.Credentials = credentials
    
                Using downloadResponse As FtpWebResponse = downloadRequest.GetResponse(),
                      sourceStream As Stream = downloadResponse.GetResponseStream(),
                      targetStream As Stream = File.Create(localFilePath)
                    Dim buffer As Byte() = New Byte(10240 - 1) {}
                    Dim read As Integer
                    Do
                        read = sourceStream.Read(buffer, 0, buffer.Length)
                        If read > 0 Then
                            targetStream.Write(buffer, 0, read)
                        End If
                    Loop While read > 0
                End Using
            End If
        Next
    End Sub
    

    使用如下函数:

    Dim credentials As NetworkCredential = New NetworkCredential("user", "mypassword")
    Dim url As String = "ftp://ftp.example.com/directory/to/download/"
    DownloadFtpDirectory(url, credentials, "C:\target\directory")
    

    如果您想避免解析服务器特定目录列表格式的麻烦,请使用支持MLSD 命令和/或解析各种LIST 列表格式的第三方库;和递归下载。

    例如使用WinSCP .NET assembly,您只需调用Session.GetFiles即可下载整个目录:

    ' Setup session options
    Dim SessionOptions As SessionOptions = New SessionOptions
    With SessionOptions
        .Protocol = Protocol.Ftp
        .HostName = "ftp.example.com"
        .UserName = "user"
        .Password = "mypassword"
    End With
    
    Using session As Session = New Session()
        ' Connect
        session.Open(SessionOptions)
    
        ' Download files
        session.GetFiles("/directory/to/download/*", "C:\target\directory\*").Check()
    End Using
    

    如果服务器支持,WinSCP 在内部使用MLSD 命令。如果没有,它使用LIST 命令并支持数十种不同的列表格式。

    Session.GetFiles method 默认是递归的。

    (我是 WinSCP 的作者)

    【讨论】:

    • 这返回 550 文件不可用 :(
    • 你说的"this"指的是什么?
    • 我的回答中有两种完全不同的解决方案。你指的是哪一个?
    猜你喜欢
    • 1970-01-01
    • 2016-08-30
    • 1970-01-01
    • 2011-07-10
    • 1970-01-01
    • 2016-09-02
    相关资源
    最近更新 更多