Thư viện AlexFTPS được sử dụng trong hàng đợi stion dường như đã chết (không được cập nhật từ năm 2011).
Hoặc, bạn có thể thử triển khai tính năng này mà không cần bất kỳ thư viện bên ngoài nào. Nhưng thật không may, cả .NET Framework lẫn PowerShell đều không có hỗ trợ rõ ràng để tải xuống tất cả các tệp trong một thư mục (chỉ cho phép tải xuống tệp đệ quy).
Bạn cần phải thực hiện điều đó bản thân:
- Danh sách thư mục ở xa
- iterate mục, tập tin tải về (và tùy chọn recursing vào thư mục con - liệt kê chúng lần nữa, vv)
Phần khó hiểu là xác định tệp từ thư mục con. Không có cách nào để thực hiện điều đó theo cách di động với khung công tác .NET (FtpWebRequest
hoặc WebClient
). Khuôn khổ .NET tiếc là không hỗ trợ lệnh MLSD
, đó là cách duy nhất để lấy danh sách thư mục với các thuộc tính tệp trong giao thức FTP. Xem thêm Checking if object on FTP server is file or directory.
lựa chọn của bạn là:
- Nếu bạn biết rằng thư mục không chứa bất kỳ thư mục con, sử dụng các phương pháp
ListDirectory
(NLST
FTP lệnh) và chỉ cần tải về tất cả các "tên" như tập tin.
- Thực hiện thao tác trên tên tệp nhất định không thành công đối với tệp và thành công đối với các thư mục (hoặc ngược lại). I E. bạn có thể thử tải xuống "tên".
- Bạn có thể may mắn và trong trường hợp cụ thể của bạn, bạn có thể nói với một tập tin từ một thư mục bằng một tên tập tin (ví dụ: tất cả các file của bạn có một phần mở rộng, trong khi thư mục con không)
- Bạn sử dụng một thư mục dài niêm yết (
LIST
phương thức command = ListDirectoryDetails
) và thử phân tích cú pháp một danh sách máy chủ cụ thể. Nhiều máy chủ FTP sử dụng danh sách * nix-style, trong đó bạn xác định một thư mục theo số d
ở đầu mục nhập. Nhưng nhiều máy chủ sử dụng một định dạng khác. Ví dụ sau đây sử dụng phương pháp này (giả sử các định dạng * 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()
}
}
}
Sử dụng các chức năng như:
$credentials = New-Object System.Net.NetworkCredential("user", "mypassword")
$url = "ftp://ftp.example.com/directory/to/download/"
DownloadFtpDirectory $url $credentials "C:\target\directory"
Mã này được dịch từ # ví dụ C của tôi trong C# Download all files and subdirectories through FTP.
Nếu bạn muốn tránh rắc rối với phân tích các danh sách thư mục định dạng máy chủ cụ thể, sử dụng một thư viện của bên thứ 3 để hỗ trợ các MLSD
lệnh và/hoặc phân tích khác nhau LIST
định dạng niêm yết. Và lý tưởng nhất là hỗ trợ tải xuống tất cả các tệp từ thư mục hoặc thậm chí tải xuống đệ quy.
Ví dụ với WinSCP .NET assembly bạn có thể tải toàn bộ thư mục với một cuộc gọi duy nhất để 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()
}
Bên trong, WinSCP sử dụng lệnh MLSD
, nếu được hỗ trợ bởi máy chủ. Nếu không, nó sử dụng lệnh LIST
và hỗ trợ hàng chục định dạng danh sách khác nhau.
Session.GetFiles
method được đệ quy theo mặc định.
(Tôi là tác giả của WinSCP)
Nếu $ remotepickupdir = get-childitem c: \ -recurse kiểm tra, PowerShell sẽ cố gắng để có được tất cả các mục ở con đường mà khi nó đặt lên biến. Vì vậy, nó không thể lấy các mục từ xa bởi vì tại thời điểm này thậm chí không có một đăng nhập. Mã của bạn có vẻ sai. – BSAFH
Điều này không được đánh dấu là đã được chấp nhận. Điều này không trả lời câu hỏi! –