简体   繁体   English

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

[英]How to download directories from FTP using VB.NET

I am trying to download multiple directories from FTP server to my local machine,我正在尝试将多个目录从 FTP 服务器下载到我的本地机器,

I have tried this,我试过这个,

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, 0, buffer.Length)
                    fs.Write(buffer, 0, 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

But here the problem is that I am able to download multiple files from folders, but unable to download the sub directories and their contents from the main directory.但这里的问题是我可以从文件夹下载多个文件,但无法从主目录下载子目录及其内容。

Basically the main directory consist of files and sub directories both.基本上主目录由文件和子目录组成。 So is there any possible way to download sub directory and its contents from FTP?那么有没有办法从FTP下载子目录及其内容?

Thanks in advance.提前致谢。

Translating my answer to C# Download all files and subdirectories through FTP to VB.NET:将我对C# 的回答翻译通过 FTP所有文件和子目录下载到 VB.NET:

The FtpWebRequest does not have any explicit support for recursive file download (or any other recursive operation). FtpWebRequest对递归文件下载(或任何其他递归操作)没有任何明确的支持。 You have to implement the recursion yourself:您必须自己实现递归:

  • List the remote directory列出远程目录
  • Iterate the entries, downloading files and recursing into subdirectories (listing them again, etc.)迭代条目,下载文件并递归到子目录(再次列出它们等)

A tricky part is to identify files from subdirectories.一个棘手的部分是从子目录中识别文件。 There's no way to do that in a portable way with the FtpWebRequest .无法使用FtpWebRequest以可移植的方式做到这一点。 The FtpWebRequest unfortunately does not support the MLSD command, which is the only portable way to retrieve directory listing with file attributes in FTP protocol.不幸的是, FtpWebRequest不支持MLSD命令,这是在 FTP 协议中检索具有文件属性的目录列表的唯一可移植方式。 See also Checking if object on FTP server is file or directory .另请参阅检查 FTP 服务器上的对象是文件还是目录

Your options are:您的选择是:

  • Do an operation on a file name that is certain to fail for file and succeeds for directories (or vice versa).对文件名进行操作,对于文件肯定会失败而对于目录会成功(反之亦然)。 Ie you can try to download the "name".即您可以尝试下载“名称”。 If that succeeds, it's a file, if that fails, it's a directory.如果成功,它是一个文件,如果失败,它是一个目录。
  • You may be lucky and in your specific case, you can tell a file from a directory by a file name (ie all your files have an extension, while subdirectories do not)您可能很幸运,在您的特定情况下,您可以通过文件名区分目录中的文件(即所有文件都有扩展名,而子目录没有)
  • You use a long directory listing ( LIST command = ListDirectoryDetails method) and try to parse a server-specific listing.您使用长目录列表( LIST命令 = ListDirectoryDetails方法)并尝试解析特定于服务器的列表。 Many FTP servers use *nix-style listing, where you identify a directory by the d at the very beginning of the entry.许多 FTP 服务器使用 *nix 样式的列表,您可以通过条目开头的d标识目录。 But many servers use a different format.但是许多服务器使用不同的格式。 The following example uses this approach (assuming the *nix format)以下示例使用此方法(假设为 *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

Use the function like:使用如下函数:

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")

If you want to avoid troubles with parsing the server-specific directory listing formats, use a 3rd party library that supports the MLSD command and/or parsing various LIST listing formats;如果您想避免解析特定于服务器的目录列表格式的麻烦,请使用支持MLSD命令和/或解析各种LIST列表格式的第 3 方库; and recursive downloads.和递归下载。

For example with WinSCP .NET assembly you can download whole directory with a single call to the Session.GetFiles :例如,使用WinSCP .NET 程序集,您可以通过一次调用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

Internally, WinSCP uses the MLSD command, if supported by the server.如果服务器支持,WinSCP 在内部使用MLSD命令。 If not, it uses the LIST command and supports dozens of different listing formats.如果没有,它使用LIST命令并支持数十种不同的列表格式。

The Session.GetFiles method is recursive by default. Session.GetFiles方法默认是递归的。

(I'm the author of WinSCP) (我是 WinSCP 的作者)

Check out my FTP class: Its pretty straight forward.查看我的 FTP 课程:非常简单。

Take a look at my FTP class, it might be exactly what you need.看看我的 FTP 类,它可能正是您所需要的。

Public Class FTP
        '-------------------------[BroCode]--------------------------
        '----------------------------FTP-----------------------------
        Private _credentials As System.Net.NetworkCredential
        Sub New(ByVal _FTPUser As String, ByVal _FTPPass As String)
            setCredentials(_FTPUser, _FTPPass)
        End Sub
        Public Sub UploadFile(ByVal _FileName As String, ByVal _UploadPath As String)
            Dim _FileInfo As New System.IO.FileInfo(_FileName)
            Dim _FtpWebRequest As System.Net.FtpWebRequest = CType(System.Net.FtpWebRequest.Create(New Uri(_UploadPath)), System.Net.FtpWebRequest)
            _FtpWebRequest.Credentials = _credentials
            _FtpWebRequest.KeepAlive = False
            _FtpWebRequest.Timeout = 20000
            _FtpWebRequest.Method = System.Net.WebRequestMethods.Ftp.UploadFile
            _FtpWebRequest.UseBinary = True
            _FtpWebRequest.ContentLength = _FileInfo.Length
            Dim buffLength As Integer = 2048
            Dim buff(buffLength - 1) As Byte
            Dim _FileStream As System.IO.FileStream = _FileInfo.OpenRead()
            Try
                Dim _Stream As System.IO.Stream = _FtpWebRequest.GetRequestStream()
                Dim contentLen As Integer = _FileStream.Read(buff, 0, buffLength)
                Do While contentLen <> 0
                    _Stream.Write(buff, 0, contentLen)
                    contentLen = _FileStream.Read(buff, 0, buffLength)
                Loop
                _Stream.Close()
                _Stream.Dispose()
                _FileStream.Close()
                _FileStream.Dispose()
            Catch ex As Exception
                MessageBox.Show(ex.Message, "Upload Error: ", MessageBoxButtons.OK, MessageBoxIcon.Error)
            End Try
        End Sub
        Public Sub DownloadFile(ByVal _FileName As String, ByVal _ftpDownloadPath As String)
            Try
                Dim _request As System.Net.FtpWebRequest = System.Net.WebRequest.Create(_ftpDownloadPath)
                _request.KeepAlive = False
                _request.Method = System.Net.WebRequestMethods.Ftp.DownloadFile
                _request.Credentials = _credentials
                Dim _response As System.Net.FtpWebResponse = _request.GetResponse()
                Dim responseStream As System.IO.Stream = _response.GetResponseStream()
                Dim fs As New System.IO.FileStream(_FileName, System.IO.FileMode.Create)
                responseStream.CopyTo(fs)
                responseStream.Close()
                _response.Close()
            Catch ex As Exception
                MessageBox.Show(ex.Message, "Download Error: ", MessageBoxButtons.OK, MessageBoxIcon.Error)
            End Try
        End Sub
        Public Function GetDirectory(ByVal _ftpPath As String) As List(Of String)
            Dim ret As New List(Of String)
            Try
                Dim _request As System.Net.FtpWebRequest = System.Net.WebRequest.Create(_ftpPath)
                _request.KeepAlive = False
                _request.Method = System.Net.WebRequestMethods.Ftp.ListDirectoryDetails
                _request.Credentials = _credentials
                Dim _response As System.Net.FtpWebResponse = _request.GetResponse()
                Dim responseStream As System.IO.Stream = _response.GetResponseStream()
                Dim _reader As System.IO.StreamReader = New System.IO.StreamReader(responseStream)
                Dim FileData As String = _reader.ReadToEnd
                Dim Lines() As String = FileData.Split(New String() {Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries)
                For Each l As String In Lines
                    ret.Add(l)
                Next
                _reader.Close()
                _response.Close()
            Catch ex As Exception
                MessageBox.Show(ex.Message, "Directory Fetch Error: ", MessageBoxButtons.OK, MessageBoxIcon.Error)
            End Try
            Return ret
        End Function

        Private Sub setCredentials(ByVal _FTPUser As String, ByVal _FTPPass As String)
            _credentials = New System.Net.NetworkCredential(_FTPUser, _FTPPass)
        End Sub
    End Class

To initialize:初始化:

Dim ftp As New FORM.FTP("username", "password")

ftp.UploadFile("c:\file.jpeg", "ftp://domain/file.jpeg")

ftp.DownloadFile("c:\file.jpeg", "ftp://ftp://domain/file.jpeg")

Dim directory As List(Of String) = ftp.GetDirectory("ftp://ftp.domain.net/")
        ListBox1.Items.Clear()
        For Each item As String In directory
            ListBox1.Items.Add(item)
        Next

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM