Перевод моего ответа на C# Загрузка всех файлов и подкаталогов через FTP в VB.NET:
FtpWebRequest
не имеет явной поддержки рекурсивной загрузки файлов (или любой другой рекурсивной операции). Вы должны реализовать рекурсию самостоятельно:
- Список удаленного каталога
- Повторите записи, загрузив файлы и рекурсивно по подкаталогам (снова перечислив их и т. д.)
Сложной частью является идентификация файлов из подкаталогов. Невозможно сделать это переносимым способом с помощью FtpWebRequest
. К сожалению, FtpWebRequest
не поддерживает команду MLSD
, которая является единственным переносимым способом получения списка каталогов с атрибутами файлов в протоколе FTP. См. также Проверка того, является ли объект на FTP-сервере файлом или каталогом.
Ваши варианты:
- Выполните операцию над именем файла, которая наверняка завершится ошибкой для файла и будет успешной для каталогов (или наоборот). т.е. можно попробовать скачать "имя". Если это удается, это файл, если нет, это каталог.
- Вам может повезти, и в вашем конкретном случае вы можете отличить файл от каталога по имени файла (т.е. все ваши файлы имеют расширение, а подкаталоги - нет)
- Вы используете длинный список каталогов (команда
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 вы можете загрузить весь каталог одним вызовом 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
по умолчанию является рекурсивным.
(я автор WinSCP)
person
Martin Prikryl
schedule
23.10.2017