C# SFTP 20210312 https://blog.darkthread.net/blog/sftp-with-csharp/ https://www.rebex.net/buru-sftp-server/ 近幾年來,網站全面改用 HTTPS 加密傳輸已是業界共識,違者會被 Google 調降搜尋結果排名,被 Chrome 在額頭刺上【不安全】。同樣的,檔案傳輸協定 FTP 如不升級成加密版 SFTP,也一樣會被資安單位盯上要求改善。過去寫過 C# FTP 上傳、下載範例,如今也該與時俱進,研究一下 C# 如何 SFTP 下載上傳。 https://www.sftp.net/ 這個網站蒐集鉅細靡遣的 SFTP 資訊,是學習使用 SFTP 的絕佳登山口。.NET 已有不少現成的 SFTP 客戶端程式庫,包含 SSH.NET、SharpSSH、WinSCP Library、Rebex File Transfer Pack (商用軟體)、Chikat SFTP Library... 等,評估之後,我選擇最多人用的開源專案 SSH.NET,它支援範圍廣泛,通吃 .NET 3.5、.NET Core、UWP、Silverlight、Windows Phone (時代的眼淚呀...),學一套吃天下: .NET Framework 3.5 .NET Framework 4.0 (and higher) .NET Standard 1.3 Silverlight 4 Silverlight 5 Windows Phone 7.1 Windows Phone 8.0 Universal Windows Platform 10 老樣子,用 NuGet 查詢 ssh.net 安裝到專案就可開打: 要跑測試的話,網路上有免費的公開 SFTP Server,但都是唯讀只能測試下載。所幸,有很多免費 SFTP Server,我挑了最簡便的 Buru Server,下載 FREE 版(限個人及學術用)解壓縮,兩行指令就搞定:(第一次執行會顯示找不到 keys 目錄錯誤,但馬上會自動產生金鑰,不用擔心) buru user add demo --rootdir D:\SFtpRoot --password demo buru run 以下是個簡單範例,包含登入、建立資料夾、上傳檔案、將檔案搬到不同資料夾、刪除檔案、刪除目錄等各程序,應可涵蓋大部分應用 SFTP 的場景: using Renci.SshNet; using Renci.SshNet.Sftp; using System; using System.IO; using System.Linq; using System.Text; namespace SFTPTest { class Program { static void Main(string[] args) { //實務應用時,帳號密碼應加密儲存於設定檔 using (var sftp = new SftpClient("127.0.0.1", "demo", "demo")) { sftp.Connect(); Action ShowDirOrFile = (item) => { if (item.IsDirectory) Console.WriteLine($"[{item.Name}]"); else //左靠右靠對齊 https://blog.darkthread.net/blog/string-format-alignment/ Console.WriteLine($"{item.Name:-32} {item.Length,8:N0} bytes"); }; Action Dir = (path) => { Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine($"Directory of {path}: \n"); var list = sftp.ListDirectory(path) //忽略 . 及 .. 目錄 .Where(o => !".,..".Split(',').Contains(o.Name)) .ToList(); if (list.Any()) list.ForEach(ShowDirOrFile); else { Console.ForegroundColor = ConsoleColor.DarkYellow; Console.WriteLine("No files."); } Console.WriteLine(); Console.ForegroundColor = ConsoleColor.White; }; Action WriteTitle = (title) => { Console.ForegroundColor = ConsoleColor.Cyan; Console.WriteLine(); Console.WriteLine(title); Console.WriteLine(); }; Dir("/"); WriteTitle("Create folder"); var rndName = DateTime.Now.ToString("yyyy-MM-dd"); sftp.CreateDirectory($"/{rndName}A"); Dir("/"); WriteTitle("Upload file"); using (var ms = new MemoryStream()) { var buff = Encoding.UTF8.GetBytes("Hello, World!"); ms.Write(buff, 0, buff.Length); ms.Position = 0; sftp.UploadFile(ms, $"/{rndName}A/test.txt"); } Dir($"/{rndName}A"); using (var file = new FileStream("D:\\test.txt", FileMode.Create)) { sftp.DownloadFile($"/{rndName}A/test.txt", file); } WriteTitle("Downloaded content=" + System.IO.File.ReadAllText("d:\\test.txt")); WriteTitle("Move file"); sftp.CreateDirectory($"/{rndName}B"); sftp.RenameFile($"/{rndName}A/test.txt", $"/{rndName}B/test.txt"); Dir($"/{rndName}A"); Dir($"/{rndName}B"); WriteTitle("Delete file"); sftp.DeleteFile($"/{rndName}B/test.txt"); Dir($"/{rndName}B"); sftp.DeleteDirectory($"/{rndName}A"); sftp.DeleteDirectory($"/{rndName}B"); } Console.Read(); } } } 實測成功! Posted in .NET and has 0 comments