TIPS-Implement a Resumable FTP Download with .NET 2.0

最近手上的案子需要以FTP方式取回數百MB到上GB的ZIP檔案,過去我的做法會一個登入及下載的Script,作為FTP command line utility的輸入來源,再以Shell方式啟動,如以下的例子:

   1:  //產生FTP Script檔案
   2:  string ftpScriptFile = Server.MapPath("TempFolder\\ftp.script");
   3:  Process p = new Process();
   4:  StreamWriter sw = 
   5:      new StreamWriter(ftpScriptFile);
   6:  sw.WriteLine("username");
   7:  sw.WriteLine("password");
   8:  sw.WriteLine("bin");
   9:  sw.WriteLine("cd /download");
  10:  sw.WriteLine("get some.zip");
  11:  sw.WriteLine("quit");
  12:  sw.Close();
  13:  //呼叫FTP command line utility
  14:  p.StartInfo = new ProcessStartInfo("cmd.exe", 
  15:  "/c ftp -s:\"" + ftpScriptFile + "\" ftp.darkthread.net");
  16:  //不顯示FTP Cmd視窗
  17:  p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
  18:  p.Start();
  19:  p.WaitForExit();
  20:  //狡兔死 走狗烹 Script檔刪除
  21:  File.Delete(ftpScriptFile);

 這個方法不算漂亮,但是簡單耐用,也不太會出錯。

之前瞄過.NET 2.0的新功能,知道它多了支援FTP的內建物件--System.Net.FtpWebRequest,更讚的是,它居然還可以支援斷線續傳的功能,對於這次可能破GB的大檔下載來說,真是一整個酷呀!

不囉嗦! 程式範例如下:

   1:  private void test()
   2:  {
   3:      //宣告FTP連線
   4:      FtpWebRequest ftpReq = (FtpWebRequest)
   5:          WebRequest.Create("ftp://ftp.darkthread.net/download/some.zip");
   6:      //下載檔案
   7:      ftpReq.Method = WebRequestMethods.Ftp.DownloadFile;
   8:      //指定Username/Password
   9:      ftpReq.Credentials = new NetworkCredential("username", "password");
  10:      //指定BIN模式
  11:      ftpReq.UseBinary = true;
  12:      string zipFile = "c:\\temp\some.zip";
  13:      //支援續傳功能
  14:      FileInfo fi = new FileInfo(zipFile);
  15:      FileStream fs = null;
  16:      //檢測檔案是否存在
  17:      if (fi.Exists)
  18:      {
  19:          //檔案若存在,由剛才的中斷點繼續
  20:          ftpReq.ContentOffset = fi.Length;
  21:          fs = new FileStream(zipFile, FileMode.Append, FileAccess.Write);
  22:      }
  23:      else //檔案不存在時重新建立新檔案
  24:          fs = new FileStream(zipFile, FileMode.Create, FileAccess.Write);
  25:      //建立FTP連線
  26:      FtpWebResponse ftpResp = (FtpWebResponse)ftpReq.GetResponse();
  27:      //取得下載用的Stream物件
  28:      using (Stream stm = ftpResp.GetResponseStream())
  29:      {
  30:          //由於檔案龐大,以Block方式多批寫入
  31:          byte[] buff = new byte[2048];
  32:          int len = 0;
  33:          while (fs.Length < ftpResp.ContentLength)
  34:          {
  35:              //取得資料長度
  36:              len = stm.Read(buff, 0, buff.Length);
  37:              fs.Write(buff, 0, len);
  38:          }
  39:          stm.Close();
  40:   
  41:      }
  42:      fs.Flush();
  43:      fs.Close();
  44:  }

Update @ 2007-06-27
以上的程式碼在下載大型檔案時會因超過FTP Server Control Connection Timeout而發生Connection Closed Exception,詳情請看這裡

Published 23 June 2007 07:00 AM 由 Jeffrey


意見

# SGY said on 03 April, 2008 12:57 PM

Good Job!

# FLY said on 05 August, 2008 01:15 AM

您好:

 測試此段程式時會掛在此處

//建立FTP連線  26:      FtpWebResponse ftpResp = (FtpWebResponse)ftpReq.GetResponse();

訊息:基礎連接已關閉: 接收時發生未預期的錯誤。

用的是"220 Serv-U FTP Server v6.1 for WinSock ready...\r\n"

# Jeffrey said on 05 August, 2008 05:12 AM

to FLY, 是在傳大檔案時才會發生還是任何檔案都不OK,我自己有遇到IIS FTP在傳大檔案時有同樣的錯誤訊息(見文末的連結),而Google的結果似乎也有人回報這類問題只發生在某些FTP Server上,我推測跟FTP Server的行為或回應的訊息格式有關。如果要查個水落石出,似乎只能靠Ethereal或Microsoft Network Monitor這類工具吧。

# FLY said on 07 August, 2008 11:26 PM

Jeffrey:

 是所有檔案都不OK,在FTP LOG上發現以下訊息

dos command直接連線是可以的。FTP上的log只有三行..

(061326) Connected to 168.0.0.1(Local address

10.1.1.1)

(061326) IP-Name: COMP006.UUU.COM

(061326) Closing connection

好像連登入都沒有,就被踢出來了。

# SoWn said on 16 March, 2010 04:41 PM

請問一下~

不知道您有沒有試過 FTP 上頭是中文檔名的 Case

因為我試了很久, 始終無法成功, 似乎中文檔名連結會找不到咧

感謝

# Jeffrey said on 17 March, 2010 12:00 AM

to SoWn, 想問一下, FTP Server的平台是UNIX嗎?

你的看法呢?

(必要的) 
(必要的) 
(選擇性的)
(必要的) 

請輸入以上的數字:

搜尋

Go

<June 2007>
SunMonTueWedThuFriSat
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567
 
RSS
【工商服務】
最新回應

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


BlogLook Score and Rank

Syndication