利用backgroundwork----遞歸讀取網頁源代碼,並下載href鏈接中的文件,
今天閒著沒事,研究了一下在線更新程序版本的問題。也是工作中的需要,開始不知道如何下手,各種百度也沒有找到自己想要的,因為我的需求比較簡單,所以就自己琢磨了一下。講講我的需求吧。自己在IIs上發布了一個網站,這個網站僅僅只是內部使用的,網站的內容就是我的另外一個程序(就叫A程序吧)的打包發布的文件放進去。然後在客戶端啟動我的A程序之前檢查是否有新版本文件發布。如果有,我根據網頁源代碼的信息和本地文件信息進行比較,決定是否下載。如果有下載,下載完成後執行A程序的.exe文件啟動A程序。大致的要求就是這樣。
首先自己發布一個測試網站,也就是簡單的在IIS上將我本機的一個文件夾發布出來,具體怎麼操作就不做講解了。得到我的網址:http://localhost/webTest/。這個網站就作為我以後有新版本文件要發布就直接丟進去。

上面的截圖中有幾個地方需要注明一下:
1.是這個文件最後一次編輯日期。
2.是最後一次編輯時間點。
3.是你這個文件的大小。
4.橢圓部分是一個文件夾。
前面標題說用遞歸,就是因為網站中可能存在子文件夾,遇到子文件夾我就要繼續跟進去讀取源代碼獲取我要的信息。
注:網頁中有個[to parent Directory]這是他的父文件夾,我們在讀取網頁源代碼的時候要對這部分進行處理
注:1,2部分是指這個文件最後一次編輯時間,比如說你在本地有個文件你對他進行最後一次的編輯時間2016/8/26 13:15 那不管你把這個文件拷貝或是上傳到其他地方,那他的編輯時間始終不會變的。
大致的情況介紹的差不多了,接下來直接開始我的讀取網頁下載文件的程序吧!上代碼,一如既往,圖文並茂的文章才是好文章。
一、創建一個winform工程。

圖(1):工程結構

圖(2):winform需要的控件
圖(1)中我添加了兩個幫助類:FileHelper.cs/HttpHelper.cs。在後面做詳細介紹
圖(2)中1是一個label控件,用來顯示正在下載的文件名。2是progressBar控件,winform自帶的進度條控件,我覺得還挺好用的。。還需要一個backgroundwork控件
二:幫助類文件
FileHelper.cs幫助類文件。

![]()
1 public class FileHelper
2 {
3 public DateTime ModiDate { get; set; } //最後編輯時間
4
5 public long Size { get; set; } //文件大小
6
7 public String FilePath { get; set; } //路徑+文件名
8 }
View Code
HttpHelper.cs

![]()
1 /// <summary>
2 /// 獲取網頁源代碼
3 /// </summary>
4 /// <param name="serverUrl">網址</param>
5 /// <param name="listFile">存放下載文件的集合</param>
6 /// <param name="listHref">存放子目錄集合</param>
7
8 public static void GetHtmlResource(string serverUrl, List<FileHelper> listFile, List<string> listHref)
9 {
10 #region
11 //Uri u = new Uri(serverUrl);
12 //string host = u.Host;
13 //if (serverUrl.EndsWith("/"))
14 //{
15 // //1.獲取網頁源代碼
16 // WebClient wc = new WebClient();
17 // wc.Credentials = CredentialCache.DefaultCredentials;
18 // byte[] htmlData = wc.DownloadData(serverUrl);
19 // string htmlStr = Encoding.Default.GetString(htmlData);
20 // //2.正則找到href屬性內容截取
21 // string regMat = @"(?is)<a[^>]*?href=(['""\s]?)(?<href>[^'""\s]*)\1[^>]*?";
22 // MatchCollection mat = Regex.Matches(htmlStr, regMat, RegexOptions.IgnoreCase);
23 // List<string> listHref = new List<string>(); //存放href結合
24 // for (int i = 0; i < mat.Count; i++)
25 // {
26 // string item = mat[i].Groups["href"].Value;
27 // listHref.Add(item);
28 // MatchCollection match = Regex.Matches(htmlStr, "([0-9]{1,})\\s\\<A\\sHREF=\""+ item+"\"", RegexOptions.IgnoreCase);
29 // if(match.Count == 1 && match[0].Groups.Count==2)
30 // {
31 // fileSize.Add(@"http://" + host + item, int.Parse(match[0].Groups[1].Value));
32 // }
33 // }
34 // foreach (var item in listHref) //Match item in mat
35 // {
36 // string url = @"http://"+host + item;
37 // if (serverUrl.StartsWith(url))
38 // {
39 // continue;
40 // }
41 // GetHtmlResource(url, serverFilePath,fileSize);
42 // }
43 //}
44 //else
45 //{
46 // serverFilePath.Add(serverUrl);
47 //}
48 #endregion
49
50 Uri u = new Uri(serverUrl);
51 string host = u.Host;
52 if (serverUrl.EndsWith("/"))
53 {
54 //1.獲取網頁源代碼
55 WebClient wc = new WebClient();
56 wc.Credentials = CredentialCache.DefaultCredentials;
57 byte[] htmlData = wc.DownloadData(serverUrl);
58 string htmlTempStr = Encoding.Default.GetString(htmlData);
59 //完全用字符串截取的方式得到自己想要的東西
60 htmlTempStr = htmlTempStr.Substring(htmlTempStr.IndexOf("<pre>"));
61 htmlTempStr = htmlTempStr.Substring(0, htmlTempStr.IndexOf("</pre>"));
62 htmlTempStr = htmlTempStr.Replace("<pre>", "");
63 htmlTempStr = htmlTempStr.Replace("</pre>", "");
64 htmlTempStr = htmlTempStr.Replace("<dir>", "-1"); //把子菜單前面的"<dir&"改為-1,為了跟其他的信息一致有規律
65 htmlTempStr = htmlTempStr.Replace("<br>", "#");
66 string[] tempStr = htmlTempStr.Split('#');
67 ArrayList listStr = new ArrayList(tempStr);
68 //移除每個新網頁的父級文件夾
69 listStr.RemoveAt(0);
70 for (int i = 0; i < listStr.Count; i++)
71 {
72 if (String.IsNullOrWhiteSpace(listStr[i].ToString()))
73 {
74 listStr.RemoveAt(i);
75 }
76 }
77 tempStr = (string[])listStr.ToArray(typeof(string));
78
79 for (int f = 0; f < tempStr.Length; f++)
80 {
81 //截取最後修改日期帶時間
82 string fileModiTime = tempStr[f].Substring(0, 20);
83 //截取文件大小
84 string fileSize = tempStr[f].Substring(20, tempStr[f].IndexOf("<A") - 20);
85 //截取文件路徑
86 string filePath = tempStr[f].Split('\"')[1];
87 FileHelper file = new FileHelper();
88 file.ModiDate = Convert.ToDateTime(fileModiTime.Trim());
89 file.Size = Convert.ToInt32(fileSize.Trim());
90 file.FilePath = @"http://" + host + filePath;
91 //如果大小為-1,我就認為是子文件夾,添加到集合中
92 if (file.Size == -1)
93 {
94 listHref.Add(file.FilePath);
95 }
96 else
97 {
98 //添加到要下載的文件集合中
99 listFile.Add(file);
100 }
101 }
102 //循環我的子文件夾集合
103 foreach (var item in listHref)
104 {
105 //如果item等於我的serverUrl繼續
106 if (serverUrl.StartsWith(item))
107 {
108 continue;
109 }
110 //遞歸
111 GetHtmlResource(item, listFile, listHref);
112 }
113
114 }
115 }
View Code

![]()
1 /// <summary>
2 /// 下載文件
3 /// </summary>
4 /// <param name="serverUrl">文件在服務器的全路徑</param>
5 /// <param name="localFilePath">下載到本地的路徑</param>
6 public static void DownLoadMdiFile(string serverUrl,string localFilePath)
7 {
8 //localFilePath = localFilePath.Replace(".exe.config.xml", ".exe.config");
9 if (localFilePath.Contains(".exe.config.xml"))
10 {
11 localFilePath = localFilePath.Replace(".exe.config.xml", ".exe.config");
12 }
13 if (localFilePath.Contains(".config.xml"))
14 {
15 localFilePath = localFilePath.Replace(".config.xml", ".config");
16 }
17 //網頁中子文件夾是否存在,如果不存在,創建文件夾,存在直接下載文件
18 FileInfo file = new FileInfo(localFilePath);
19 if(!file.Directory.Exists)
20 {
21 Directory.CreateDirectory(file.Directory.FullName);
22
23 }
24 try
25 {
26 WebClient wc = new WebClient();
27 if (!localFilePath.Contains("web.config"))
28 {
29 wc.DownloadFile(serverUrl, localFilePath);
30 }
31 }
32 catch (Exception e)
33 {
34 throw;
35 }
36 }
View Code
三:banckgroundwork控件
對於這個控件我需要實現他的三個事件。很簡單的三個事件,看事件名稱就能知道他的意思了
第一個:backgroundWorker1_DoWork

![]()
1 private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
2 {
3 #region
4 //string installUrl = GetInstallPath();
5 //List<string> listFilePath = new List<string>();
6 //Dictionary<string, int> fileSize = new Dictionary<string, int>();
7 //HttpHelper.GetHtmlResource(installUrl, listFilePath, fileSize);
8 //for (int i=0;i<listFilePath.Count;i++)
9 //{
10 // if (backgroundWorker1.CancellationPending)
11 // {
12 // e.Cancel = true;
13 // return;
14 // }
15 // double total = listFilePath.Count;
16 // double current = i+1;
17 // int progress = (int)(current / total * 100);
18 // string serverUrl = listFilePath[i];
19 // int size = fileSize[serverUrl];
20 // backgroundWorker1.ReportProgress(progress, serverUrl.Replace(installUrl, ""));
21 // string localPath = serverUrl.Replace(installUrl, localInstallPath);
22 // if (File.Exists(localPath))
23 // {
24 // FileStream fs = new FileStream(localPath, FileMode.Open);
25
26 // if (fs.Length != size)
27 // {
28 // try
29 // {
30 // HttpHelper.DownLoadMdiFile(serverUrl, localPath);
31 // }
32 // catch (Exception )
33 // {
34 // throw;
35 // }
36 // }
37 // fs.Close();
38 // }
39 // else
40 // {
41 // HttpHelper.DownLoadMdiFile(serverUrl, localPath);
42 // }
43 //}
44 #endregion
45 string installUrl = GetInstallPath();
46 List<string> listHref = new List<string>();//存放子文件夾集合
47 List<FileHelper> listFile = new List<FileHelper>();//存放下載文件集合
48 HttpHelper.GetHtmlResource(installUrl, listFile, listHref);
49 for (int i = 0; i < listFile.Count; i++)
50 {
51 if (backgroundWorker1.CancellationPending)
52 {
53 e.Cancel = true;
54 return;
55 }
56 double total = listFile.Count;
57 double current = i + 1;
58 int progress = (int)(current / total * 100);
59 //服務器文件+全路徑
60 string serverUrl = listFile[i].FilePath;
61 //服務器文件大小
62 long size = listFile[i].Size;
63 //服務器文件最後修改時間
64 DateTime modiTine = listFile[i].ModiDate;
65 //backgroundWorker1執行到那個階段
66 backgroundWorker1.ReportProgress(progress, serverUrl.Replace(installUrl, ""));
67 string localPath = serverUrl.Replace(installUrl, localInstallPath);
68 //判斷文件是否存在
69 if (File.Exists(localPath))
70 {
71 //獲取本地文件
72 FileInfo fs = new FileInfo(localPath);
73 //如果服務器文件大小,最後修改時間和本地文件進行對比,是否有變化
74 if (fs.Length != size || fs.LastWriteTime != modiTine)
75 {
76
77 try
78 {
79 HttpHelper.DownLoadMdiFile(serverUrl, localPath);
80 }
81 catch (Exception)
82 {
83
84 throw;
85 }
86 }
87
88 }
89 else
90 {
91 HttpHelper.DownLoadMdiFile(serverUrl, localPath);
92 }
93 }
94 }
View Code
第二個:backgroundWorker1_ProgressChanged

![]()
1 private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
2 {
3 this.progressBar.Value = e.ProgressPercentage;
4 var display = e.UserState.ToString();
5 labDisplay.Text = display.Trim();
6 //lbl_pbvalue.Text = "更新進度" + e.ProgressPercentage + "%";
7 }
View Code
第三個:backgroundWorker1_RunWorkerCompleted

![]()
1 private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
2 {
3 runningPath += "A.exe";
4 try
5 {
6 System.Diagnostics.Process.Start(runningPath);
7 }
8 catch (Exception ex)
9 {
10 MessageBox.Show(ex.Message);
11 }
12
13 this.Close();
14 }
View Code
在使用backgroundwork和progressBar控件的時候需要注意幾個點
this.backgroundWorker1.WorkerReportsProgress = true; 用於進度條更新
this.backgroundWorker1.WorkerSupportsCancellation = true; 提供中途終止進程
this.progressBar.Maximum = 100;給一個最大值
好吧!就這樣一個簡單的在線更新文件的程序就搞定啦!
【轉載注明出處!謝謝】