从VB.NET中的FTP文件夹下载所有文件和子目录

时间:2017-09-22 11:34:36

标签: .net vb.net ftp

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

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

我目前正在通过从我的FTP服务器下载ZIP文件并将其解压缩来进行此操作,但这不是一个好方法。

谢谢!

2 个答案:

答案 0 :(得分:2)

我知道你可能会懒得阅读所有这些,但这是答案!该守则即将结束: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上传的SynchronizeMode.Remote到FTP服务器,所以在下面的代码中,我用.Remote

    替换了.Local
    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
    
  3. 不要忘记更换凭据和路径..

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

答案 1 :(得分:1)

将我对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

您的选择是:

  • 对文件名执行操作,该文件名对于文件肯定会失败并对目录成功(反之亦然)。即您可以尝试下载"名称"。如果成功,它就是一个文件,如果失败,它就是一个目录。
  • 您可能很幸运,在您的具体情况下,您可以通过文件名告诉目录中的文件(即所有文件都有扩展名,而子目录则没有)
  • 您使用长目录列表(LIST command = 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的作者)