如何使用VB.NET从FTP下载目录

我试图从FTP服务器下载多个目录到我的本地机器,

我试过这个,

Const localFile As String = "C:\Documents and Settings\cr\Desktop\T\New Folder\"
Const remoteFile As String = "textbox.Text"
Const host As String = "ftp://ftp.example.com"
Const username As String = "username"
Const password As String = "password"

For i1 = 0 To ListBox1.SelectedItems.Count - 1
    Dim li As New ListViewItem
    li = ListView1.Items.Add(ListBox1.SelectedItems(i1))
    Dim URI1 As String = host + remoteFile & "/" & ListBox1.SelectedItems(i1)
    Dim ftp1 As System.Net.FtpWebRequest = CType(FtpWebRequest.Create(URI1),FtpWebRequest)
    ftp1.Credentials = New System.Net.NetworkCredential(username,password)
    ftp1.KeepAlive = False
    ftp1.UseBinary = True
    ftp1.Method = System.Net.WebRequestMethods.Ftp.DownloadFile
    Using response As System.Net.FtpWebResponse = CType(ftp1.GetResponse,System.Net.FtpWebResponse)
        Using responseStream As IO.Stream = response.GetResponseStream

            Dim length As Integer = response.ContentLength
            Dim bytes(length) As Byte

            'loop to read & write to file
            Using fs As New IO.FileStream(localFile & ListBox1.SelectedItems(i1),IO.FileMode.Create)
                Dim buffer(2047) As Byte
                Dim read As Integer = 1

                Do
                    read = responseStream.Read(buffer,buffer.Length)
                    fs.Write(buffer,read)

                Loop Until read = 0 'see Note(1)
                responseStream.Close()
                fs.Flush()
                fs.Close()
            End Using
            responseStream.Close()
        End Using

        response.Close()
    End Using
    li.BackColor = Color.Aquamarine
Next

但问题是我可以从文件夹下载多个文件,但无法从主目录下载子目录及其内容.

基本上,主目录由文件和子目录组成.那么是否有任何可能的方法从FTP下载子目录及其内容?

提前致谢.

解决方法

将我对 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命令= ListDirectoryDe​​tails方法)并尝试解析特定于服务器的列表.许多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,buffer.Length)
                    If read > 0 Then
                        targetStream.Write(buffer,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,"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的作者)

相关文章

Format[$] ( expr [ , fmt ] ) format 返回变体型 format$ 强...
VB6或者ASP 格式化时间为 MM/dd/yyyy 格式,竟然没有好的办...
在项目中添加如下代码:新建窗口来显示异常信息。 Namespace...
转了这一篇文章,原来一直想用C#做k3的插件开发,vb没有C#用...
Sub 分列() ‘以空格为分隔符,连续空格只算1个。对所选...
  窗体代码 1 Private Sub Text1_OLEDragDrop(Data As Dat...