Windows程序通用自動更新模塊(C#,.NET4.5以上)


本通用自動更新模塊適合所有Windows桌面程序的自動更新,不論語言,無論Winform還是wpf。

一、工作流程:
1. 主程序A調起升級程序B
2. B從服務器獲取更新程序列表,打印更新信息。
3. B殺死A進程(此步驟可以放在步驟2~5任意位置)
4. B根據更新信息中指示的地址,下載更新程序包(.zip文件)
5. 解壓縮.zip文件到一個新創建的文件夾
6. 將解壓后的文件拷貝到原始文件目錄,做替換。
7. 刪除下載的.zip文件以及解壓后創建的文件夾
8. B打開A

二、源碼介紹:

升級程序B的實現:

更新信息列表用於存儲版本信息,以及更新說明信息。通常為json或xml文件。本文為json文件。

存儲列表信息的類

public class UpdateItem
{
    public string Version { get; set; }  //版本號
    public string UpdateContent { get; set; }  //更新信息
    public string DownloadUri { get; set; }  //更新包的下載地址
    public string Time { get; set; }  //更新時間
    public string Size { get; set; }  //更新包大小
}

 獲取更新信息使用WebClient.DownloadData(Uri),其中使用Newtonsoft.Json進行json序列化及反序列化。

WebClient client = new WebClient();
byte[] data = client.DownloadData(uri);
//json轉為UpdateItem類對象
UpdateInfo = Newtonsoft.Json.JsonConvert.DeserializeObject<UpdateItem>(Encoding.UTF8.GetString(data));

 獲取更新信息以后在界面上進行輸出。
下面介紹一下生成更新信息的json文件並使用FTP上傳到服務器的代碼。json文件也可以手動寫,手動上傳。不是重點,不想看可以跳到下一部分。

UpdateItem UpdateInfo = new UpdateItem();
...  //賦值
string json = JsonConvert.SerializeObject(UpdateInfo);
 //連接服務器
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://...");
request.Method = WebRequestMethods.Ftp.UploadFile;
request.Credentials = new NetworkCredential("賬號", "密碼");
// 復制字符  
byte[] fileContents = Encoding.UTF8.GetBytes(json);
request.ContentLength = fileContents.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(fileContents, 0, fileContents.Length);
requestStream.Close();
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
response.Close();

下載更新包zip文件

下載使用WebClient.DownloadFile(Uri, string)

string dir = System.IO.Directory.GetCurrentDirectory();  //程序所在文件夾路徑
string zipfile = System.IO.Path.Combine(dir, "file.zip");  //下載后zip文件的完整路徑

WebClient client = new WebClient();
client.DownloadFile(UpdateInfo.DownloadUri, zipfile);
return true;

解壓縮zip文件

解壓縮需要用到System.IO.Compression.ZipFile,需要.NET4.5及以上。如果用不了(找不到ZipFile),請檢查是否已添加引用System.IO.Compression.FileSystem程序集。

代碼只有一行,兩個參數分別為zip文件完整路徑,解壓后的文件夾完整路徑。

ZipFile.ExtractToDirectory(zipfile, extractPath);

使用第三方壓縮軟件生成的.zip文件有可能會解壓失敗,建議使用下方代碼生成。兩個參數分別為需要壓縮的文件夾完整路徑,生成的zip文件完整路徑。

ZipFile.CreateFromDirectory(startPath, zipfile);

拷貝解壓后的文件到原始目錄

foreach (string item in Directory.GetFiles(extractPath))
{
    File.Copy(item, System.IO.Path.Combine(dir, System.IO.Path.GetFileName(item)), true);
}

刪除臨時文件

File.Delete(zipfile);
DirectoryInfo di = new DirectoryInfo(extractPath);
di.Delete(true);

B進程殺死A進程

string appname = "file"; //A名字,不要路徑,不要.exe
Process[] processes = Process.GetProcessesByName(appname);
foreach (var p in processes)
p.Kill();

B進程調起A進程

System.Diagnostics.Process.Start(@"path");  //完整路徑

 

主要流程就是這些,建議用異步操作實現。
現在上號比較少,私信很多要代碼的都沒回…以后都會把完整代碼附上的。
下面是完整代碼。

private Uri uri = new Uri(@"http://...");  //更新信息列表文件路徑
private UpdateItem UpdateInfo;  //UpdateItem類的定義在前面第一部分說明

public MainWindow()
{
    InitializeComponent();
    LoadingData();
}

//用戶按下更新按鈕
private async void Button_Click(object sender, RoutedEventArgs e)
{
    //下載
    Tb_State.Text = "正在下載新版本文件,請耐心等待";
    string dir = System.IO.Directory.GetCurrentDirectory();
    string zipfile = System.IO.Path.Combine(dir, "File.zip");
    bool success = await Task.Run(() =>
    {
        try
        {
            WebClient client = new WebClient();
            client.DownloadFile(UpdateInfo.DownloadUri, zipfile);
            return true;
        }
        catch (Exception)
        {
            return false;
        }
    });

    if (success)
        Tb_State.Text = "文件已下載,正在復制文件";
    else
    {
        Tb_State.Text = "下載新版本文件失敗,請重試";
        return;
    }

    //殺死主程序進程
    string appname = "File";
    Process[] processes = Process.GetProcessesByName(appname);
    foreach (var p in processes)
        p.Kill();


    //解壓縮+拷貝+刪除
    bool success2 = await Task.Run(() =>
    {
        try
        {
            string extractPath = System.IO.Path.Combine(dir, "NewVersion");
            ZipFile.ExtractToDirectory(zipfile, extractPath);
            foreach (string item in Directory.GetFiles(extractPath))
                File.Copy(item, System.IO.Path.Combine(dir, System.IO.Path.GetFileName(item)), true);
            File.Delete(zipfile);
            DirectoryInfo di = new DirectoryInfo(extractPath);
            di.Delete(true);
            return true;
        }
        catch (Exception)
        {
            return false;
        }
    });

    if (success2)
        Tb_State.Text = "更新完成,您可以點擊下方按鈕啟動應用";
    else
        Tb_State.Text = "復制更新文件出錯,請重試";
}

//讀取更新列表文件
private async Task<bool> LoadingData()
{
    Tb_State.Text = "正在下載更新文件信息";
    bool success = await Task.Run(() =>
    {
        try
        {
            WebClient client = new WebClient();
            byte[] data = client.DownloadData(uri);
            UpdateInfo = Newtonsoft.Json.JsonConvert.DeserializeObject<UpdateItem>(Encoding.UTF8.GetString(data));
            return true;
        }
        catch (Exception)
        {
            return false;
        }
    });

    if (success)
        Tb_State.Text = "已獲取新版本信息,可進行更新";
    else
        Tb_State.Text = "無法獲取更新信息";
    return success;
}

//更新完成,更新程序B調起主程序A
private void Btn_Open_Click(object sender, RoutedEventArgs e)
{
    System.Diagnostics.Process.Start(@"D:\...");   //A程序完整路徑
}

再貼一個用於下載過程中,能實時顯示已下載文件大小的代碼
此部分需寫在下載部分之前。

System.Windows.Threading.DispatcherTimer dt = new System.Windows.Threading.DispatcherTimer();
dt.Interval = TimeSpan.FromMilliseconds(100);  //100毫秒
dt.Tick += (x, y) => {
    if (File.Exists(zipfile) == false)
        return;
    string size = ((new FileInfo(zipfile).Length) / 1024.0 / 1024).ToString("f2");
    if (download == false)  //是否下載完畢
        Tb_State.Text = size + "MB / " + UpdateInfo.Size;  //輸出:已下載/總大小
    else
        dt.Stop();
};
dt.Start();

代碼部分執行時,再次執行代碼可能會報錯。可能原因包括下載zip文件后未刪除再次下載報錯等。如要做項目還有很多地方需要進行判斷,如檢測路徑的合法性等。為了代碼便於閱讀,沒有加入這些錯誤檢測部分,需自行補充。幾乎所有操作前都應判斷路徑合法性,以及目標位置的文件是否存在(是否需要先刪除)等。只能說是在輸入合法的情況下,完整執行此代碼是沒有問題的。

代碼通過Visual Studio 2019測試,.NET4.5。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM