在 WinForm 應用程式中,使用 TreeView 控制項遞迴載入遠端 FTP 伺服器的完整目錄結構(資料夾與檔案)。
public class FtpClient {
public FtpDetails Ftp { get; private set; }
private NetworkCredential _credential;
public FtpClient(FtpDetails details) {
_credential = new NetworkCredential(details.UserName, details.Password);
Ftp = details;
}
// 連線參數封裝
public class FtpDetails {
public string Host { get; set; }
public int Port { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public FtpDetails(string host, int port, string user, string pass) { ... }
}
// 錯誤事件
public event EventHandler<FtpError> ErrorMessage;
public class FtpError : EventArgs {
public string ErrUrl, ErrMsg;
public ErrType Err;
public enum ErrType { Upload, ListDirectory, CreateDirectory }
}
...
}
public string GetFileList(string strPath) {
try {
string uriStr = $"ftp://{Ftp.Host}:{Ftp.Port}" + (strPath != "" ? "/" + strPath : "");
var request = (FtpWebRequest)WebRequest.Create(uriStr);
request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
request.Credentials = _credential;
request.UsePassive = true;
using (var response = (FtpWebResponse)request.GetResponse())
using (var stream = response.GetResponseStream())
using (var reader = new StreamReader(stream, Encoding.Default)) {
return reader.ReadToEnd();
}
}
catch (Exception ex) {
OnError(new FtpError { ErrUrl = strPath, ErrMsg = ex.Message, Err = FtpError.ErrType.ListDirectory });
return "";
}
}
public class FtpListFileInfo {
public bool IsDirectory { get; set; }
public long FileSize { get; set; }
public string FileName { get; set; }
public void ParseString(string line) {
if (string.IsNullOrEmpty(line)) return;
try {
IsDirectory = line.StartsWith("d");
FileSize = long.Parse(line.Substring(30, 12).Trim());
FileName = line.Substring(55).Trim();
}
catch {
IsDirectory = false; FileSize = 0; FileName = "";
}
}
}
注意:FTP LIST 回應格式因伺服器實作而異(Unix vs Windows),上述解析假設標準 Unix 格式(權限位於開頭,大小固定欄寬)。實際部署需根據目標伺服器調整解析邏輯。
public partial class Form1 : Form {
private FtpClient _ftp;
private void Form1_Load(object sender, EventArgs e) {
var details = new FtpClient.FtpDetails("www.cnblogs.com", 21, "cnblogVIP", "**********");
_ftp = new FtpClient(details);
LoadFtpTree(treeView1.Nodes, "");
}
private void LoadFtpTree(TreeNodeCollection nodes, string path) {
string result = _ftp.GetFileList(path);
string[] lines = result.Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
int nodeIndex = -1;
foreach (string line in lines) {
var info = new FtpClient.FtpListFileInfo();
info.ParseString(line);
if (info.IsDirectory && info.FileName != ".." && info.FileName != ".") {
nodeIndex++;
nodes.Add(info.FileName); // 新增目錄節點
string newPath = path + "/" + info.FileName;
Application.DoEvents(); // 保持 UI 回應
LoadFtpTree(nodes[nodeIndex].Nodes, newPath); // 遞迴
}
else if (!info.IsDirectory) {
nodeIndex++;
nodes.Add(info.FileName); // 新增檔案節點(Tag 可存 FileSize)
}
}
treeView1.ExpandAll();
}
}
Application.DoEvents() 讓 UI 執行緒處理重繪,長時間操作建議用 BackgroundWorker 或 async/awaitUsePassive = true 穿透防火牆/NATEncoding.Default 適用中文環境,若伺服器回傳 UTF-8 需調整CreateDirectory(path):WebRequestMethods.Ftp.MakeDirectoryUploadFile(path, localFile):WebRequestMethods.Ftp.UploadFile,分塊上傳支援大檔案結合 FtpWebRequest 標準庫與遞迴演算法,可快速建構 FTP 目錄樹瀏覽器。生產環境需加強:非同步操作、快取機制、多伺服器格式相容、權限視覺化等。