NET框架或PowerShell中沒有遞歸文件操作(包括下載任何明確的支持),您必須執行遞歸自己:
- 列出遠程目錄
- 迭代項,下載文件,並在遞歸到子目錄(再次列出這些,等)
棘手的部分是從子目錄中識別文件。使用.NET框架(FtpWebRequest
或WebClient
)無法以便攜方式執行此操作。不幸的是,.NET框架不支持MLSD
命令,該命令是用FTP協議檢索具有文件屬性的目錄列表的唯一可移植方式。另請參閱Checking if object on FTP server is file or directory。
的選項有:
- 上那是一定要失敗的文件,併成功爲目錄(反之亦然)的文件名再做一次手術。即你可以嘗試下載「名稱」。如果成功,它就是一個文件,如果失敗了,它就是一個目錄。
- 你可能是幸運的,在特定情況下,可以通過文件名告訴從目錄中的文件(即所有文件的擴展名,而子目錄不)
- 您使用長的目錄列表(
LIST
命令= ListDirectoryDetails
方法)並嘗試解析服務器特定的列表。許多FTP服務器使用* nix風格的列表,其中您在入口最開始處用d
標識目錄。但是許多服務器使用不同的格式。下面的示例使用這種方法(假設* nix的格式)
function DownloadFtpDirectory($url, $credentials, $localPath)
{
$listRequest = [Net.WebRequest]::Create($url)
$listRequest.Method = [System.Net.WebRequestMethods+FTP]::ListDirectoryDetails
$listRequest.Credentials = $credentials
$lines = New-Object System.Collections.ArrayList
$listResponse = $listRequest.GetResponse()
$listStream = $listResponse.GetResponseStream()
$listReader = New-Object System.IO.StreamReader($listStream)
while (!$listReader.EndOfStream)
{
$line = $listReader.ReadLine()
$lines.Add($line) | Out-Null
}
$listReader.Dispose()
$listStream.Dispose()
$listResponse.Dispose()
foreach ($line in $lines)
{
$tokens = $line.Split(" ", 9, [StringSplitOptions]::RemoveEmptyEntries)
$name = $tokens[8]
$permissions = $tokens[0]
$localFilePath = Join-Path $localPath $name
$fileUrl = ($url + $name)
if ($permissions[0] -eq 'd')
{
if (!(Test-Path $localFilePath -PathType container))
{
Write-Host "Creating directory $localFilePath"
New-Item $localFilePath -Type directory | Out-Null
}
DownloadFtpDirectory ($fileUrl + "/") $credentials $localFilePath
}
else
{
Write-Host "Downloading $fileUrl to $localFilePath"
$downloadRequest = [Net.WebRequest]::Create($fileUrl)
$downloadRequest.Method = [System.Net.WebRequestMethods+FTP]::DownloadFile
$downloadRequest.Credentials = $credentials
$downloadResponse = $downloadRequest.GetResponse()
$sourceStream = $downloadResponse.GetResponseStream()
$targetStream = [System.IO.File]::Create($localFilePath)
$buffer = New-Object byte[] 10240
while (($read = $sourceStream.Read($buffer, 0, $buffer.Length)) -gt 0)
{
$targetStream.Write($buffer, 0, $read);
}
$targetStream.Dispose()
$sourceStream.Dispose()
$downloadResponse.Dispose()
}
}
}
使用的功能等:
$credentials = New-Object System.Net.NetworkCredential("user", "mypassword")
$url = "ftp://ftp.example.com/directory/to/download/"
DownloadFtpDirectory $url $credentials "C:\target\directory"
的代碼是從我的C#示例中C# Download all files and subdirectories through FTP翻譯。
如果你想避免與解析服務器特定的目錄列表格式的煩惱,使用支持MLSD
命令和/或解析各種LIST
房源格式第三方庫;和遞歸下載。
例如與WinSCP .NET assembly你可以用一個調用Session.GetFiles
下載整個目錄:
# Load WinSCP .NET assembly
Add-Type -Path "WinSCPnet.dll"
# Setup session options
$sessionOptions = New-Object WinSCP.SessionOptions -Property @{
Protocol = [WinSCP.Protocol]::Ftp
HostName = "ftp.example.com"
UserName = "user"
Password = "mypassword"
}
$session = New-Object WinSCP.Session
try
{
# Connect
$session.Open($sessionOptions)
# Download files
$session.GetFiles("/directory/to/download/*", "C:\target\directory\*").Check()
}
finally
{
# Disconnect, clean up
$session.Dispose()
}
內部,WinSCP賦予使用MLSD
命令,如果服務器支持。如果不是,則使用LIST
命令並支持數十種不同的列表格式。
默認情況下,Session.GetFiles
method是遞歸的。
(我的WinSCP的作者)
謝謝你很多。使用winscp完美工作! – Pascal