zoukankan      html  css  js  c++  java
  • 版本更新基本操作

    1.简介

      本文是制作了对软件进行自动更新的程序,有三个模式:

    1、模式1
    程序运行时:检查到更新,先偷偷下载,下载完成后,提示更新,手动点进行更新。开机启动时,若有完整的更新包,就进行直接更新。


    2、模式2
    程序运行时:检查到更新,提示更新,点击更新后,进行下载,下载完成后进行更新。开机启动时,若有完整的更新包,就进行直接更新。

     

    3、模式3
    程序运行时:不检查更新开机启动时,检查更新,下载更新,进行更新。

     

    2.功能分析

      1)首先,设计了一个简单的客户端Web程序,使用Wcf进行数据传输,使客户端能够通过Wcf获取项目的版本信息和更新包下载地址。

      2)设计一个客户端,在这个客户端里面,我只是随意设计了一个窗口,然后在配置文件里面写明这个客户端的详细信息。

      3)最重要的来了,更新程序,先介绍一下必要的文件夹

      

      上面四个标注的文件是写死的了,必须存在的,这四个文件也就是客户端的全部内容了,ReayProject只是我存放开发文件的文件夹,部署用不到的。

      思路:更新时下载文件更新包在临时版本库,解压,把本地版本备份到备份版本,再把临时版本库的内容同步到本地版本,完成版本更新。

      在开始写各个更新功能之前,我们先写一下需要用到什么通用的功能,所以就写了一个基础操作类,供各个更新模式调用

      BasicOperation

    using Ionic.Zip;
    using Microsoft.Win32;
    using System;
    using System.Configuration;
    using System.Diagnostics;
    using System.IO;
    using System.Net;
    using System.Security.Cryptography;
    using System.Text;
    using System.Xml;
    
    namespace UpdateProgram
    {
        /// <summary>
        /// 基础操作类
        /// </summary>
        class BasicOperation
        {
            /// <summary>
            /// 获取更新信息
            /// </summary>
            /// <param name="deploy"></param>
            /// <returns></returns>
            public virtual bool GetUpdateInfo(ref DeployModel deploy)
            {
                try
                {
                    WcfPosService.PosWcfClient client = new WcfPosService.PosWcfClient();
                    string retu = client.GetProjectVersion(deploy.ProjectName);
                    if (retu != null)
                    {
                        string[] retuArray = retu.Split(',');
                        deploy.NewVersion = Convert.ToDouble(retuArray[0].TrimStart('V'));
                        deploy.UpdateUrl = retuArray[1];
                        string[] vs = deploy.UpdateUrl.Split('/');
                        deploy.UpdateFileName = vs[vs.Length - 1];
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
            /// <summary>
            /// 关闭指定名字的服务
            /// </summary>
            /// <param name="ProcessName"></param>
            public void KillProcess(string ProcessName)
            {
                try
                {
                    Process[] processes = Process.GetProcessesByName(ProcessName);
                    foreach (Process p in processes)
                    {
                        p.Kill();
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
            /// <summary>
            /// 开启指定地址的服务
            /// </summary>
            /// <param name="ProcessPath"></param>
            public void StartProcess(string ProcessPath)
            {
                try
                {
                    Process p = new Process();
                    p.StartInfo.FileName = ProcessPath;
                    p.Start();
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
            /// <summary>
            /// 根据Url返回网络文件数据流
            /// </summary>
            /// <param name="Url"></param>
            /// <returns></returns>
            public Stream GetUrlStream(string Url)
            {
                try
                {
                    HttpWebRequest request = WebRequest.Create(Url) as HttpWebRequest;
                    HttpWebResponse response = request.GetResponse() as HttpWebResponse;
                    Stream responseStream = response.GetResponseStream();
                    return responseStream;
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
            /// <summary>
            /// 带Range根据Url返回网络文件数据流
            /// </summary>
            /// <param name="Url"></param>
            /// <param name="Range">断点续传</param>
            /// <returns></returns>
            public Stream GetUrlStreamAddRange(string Url, long Range)
            {
                try
                {
                    HttpWebRequest request = WebRequest.Create(Url) as HttpWebRequest;
                    request.AddRange((int)Range);
                    HttpWebResponse response = request.GetResponse() as HttpWebResponse;
                    Stream responseStream = response.GetResponseStream();
                    return responseStream;
                }
                catch (Exception ex)
                {
                    throw ex;
                }
    
            }
            /// <summary>
            /// 获取网络文件大小
            /// </summary>
            /// <param name="src"></param>
            /// <returns></returns>
            public long GetUrlFileLength(string Url)
            {
                try
                {
                    return WebRequest.Create(Url).GetResponse().ContentLength;
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
            /// <summary>
            /// 获取本地文件大小
            /// </summary>
            /// <param name="localFilePath"></param>
            /// <returns></returns>
            public long GetlStartPos(string localFilePath)//判断断点
            {
                try
                {
                    return new FileInfo(localFilePath).Length;
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
            /// <summary>
            /// 获取本地安装的WinRar的路径,若未安装,返回null
            /// </summary>
            /// <returns></returns>
            public string GetWinRarInstallPath()
            {
                string result = string.Empty;
                RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(@"SOFTWAREMicrosoftWindowsCurrentVersionApp PathsWinRAR.exe");
                if (registryKey != null)
                {
                    result = registryKey.GetValue("").ToString();
                }
                registryKey.Close();
                return result;
            }
            /// <summary>
            /// 解压Rar文件,需要先安装WinRar
            /// </summary>
            /// <param name="CompressFileUrl">需要解压的压缩文件</param>
            /// <param name="DecompressToDir">解压到哪个文件夹</param>
            /// <param name="WinRarPath">WinRarPath的安装目录</param>
            /// <returns>解压结果,成功为true,失败为false</returns>
            public bool DecompressFile(string CompressFileUrl, string DecompressToDir, string WinRarPath)
            {
                try
                {
                    String commandOptions = string.Format("x {0} {1} -y", CompressFileUrl, DecompressToDir);
                    string winrarDir = Path.GetDirectoryName(WinRarPath);
                    ProcessStartInfo processStartInfo = new ProcessStartInfo();
                    processStartInfo.FileName = Path.Combine(winrarDir, "rar.exe");
                    processStartInfo.Arguments = commandOptions;
                    processStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
                    Process process = new Process();
                    process.StartInfo = processStartInfo;
                    process.Start();
                    process.WaitForExit();
                    process.Close();
                    return true;
                }
                catch
                {
                    return false;
                }
            }
            /// <summary>
            /// 解压Zip文件,不会报错
            /// </summary>
            /// <param name="CompressFileUrl">Zip文件地址</param>
            /// <param name="DecompressToDir">解压到此文件夹,若无,自动生成</param>
            public void DecompressZipFile(string CompressFileUrl, string DecompressToDir)
            {
                using (ZipFile zip = new ZipFile(CompressFileUrl, Encoding.UTF8))
                {
                    zip.ExtractAll(DecompressToDir, ExtractExistingFileAction.OverwriteSilently);
                }
            }
            /// <summary>
            /// 删除指定文件夹下面的Rar和Zip压缩包
            /// </summary>
            /// <param name="Dir"></param>
            public void DeleteCompressBag(string Dir)
            {
                DirectoryInfo dir = new DirectoryInfo(Dir);
                foreach (FileInfo fi in dir.GetFiles("*.rar"))
                {
                    fi.Delete();
                }
                foreach (FileInfo fi in dir.GetFiles("*.zip"))
                {
                    fi.Delete();
                }
            }
            /// <summary>
            /// 同步文件夹里面的内容
            /// </summary>
            /// <param name="src">源地址</param>
            /// <param name="obj">目标地址</param>
            /// <param name="Complete">完全同步,true表示obj与src完全一致,false表示obj只根据src的内容进行添加和修改</param>
            public void RecursiveFile(string src, string obj, bool Complete = false)
            {
                DirectoryInfo dirSrc;
                if (Complete)
                {
                    //没实现
                    //dirSrc = new DirectoryInfo(obj);
                    //FileSystemInfo[] FileSystemInfos = dirSrc.GetFileSystemInfos();
                    //foreach (DirectoryInfo dir in FileSystemInfos)
                    //{
                    //    File.Delete(dir.Name);//清空所有
                    //}
                }
                dirSrc = new DirectoryInfo(src);
                FileInfo[] fileInfos = dirSrc.GetFiles();
                foreach (FileInfo fi in fileInfos)//同步文件
                {
                    string strsrc = src + "\" + fi.Name;
                    string strobj = obj + "\" + fi.Name;
                    if (File.Exists(strobj) == false)
                    {
                        File.Copy(strsrc, strobj, true);
                        continue;
                    }
                    //比较两个文件的MD5码
                    FileStream srcStream = new FileStream(strsrc, FileMode.Open);
                    FileStream objStream = new FileStream(strobj, FileMode.Open);
                    MD5 md5 = new MD5CryptoServiceProvider();
                    byte[] srcVal = md5.ComputeHash(srcStream);
                    byte[] objVal = md5.ComputeHash(objStream);
                    srcStream.Close();
                    objStream.Close();
                    if (byteEquals(srcVal, objVal))
                    {
                        continue;
                    }
                    File.Copy(strsrc, strobj, true);
                }
                DirectoryInfo[] dirSrcs = dirSrc.GetDirectories();
                foreach (DirectoryInfo dir in dirSrcs)//查找子目录
                {
                    string strsrc = src + "\" + dir.Name;
                    string strobj = obj + "\" + dir.Name;
                    if (Directory.Exists(strobj) == false)
                    {
                        Directory.CreateDirectory(strobj);
                    }
                    RecursiveFile(strsrc, strobj, false);
                }
            }
            /// <summary>
            /// 比较两个字节数组是否相同
            /// </summary>
            /// <param name="b1"></param>
            /// <param name="b2"></param>
            /// <returns></returns>
            public bool byteEquals(byte[] b1, byte[] b2)
            {
                for (int i = 0; i < b1.Length; i++)
                    if (b1[i] != b2[i])
                        return false;
                return true;
            }
            /// <summary>
            /// 获取指定config文件中appSettings节点下key的value
            /// </summary>
            /// <param name="key"></param>
            /// <param name="configPath"></param>
            /// <returns></returns>
            public string GetAppSettings(string key, string configPath)
            {
                ExeConfigurationFileMap map = new ExeConfigurationFileMap { ExeConfigFilename = configPath };
                var configuration = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
                var strObj = configuration.AppSettings.Settings[key];
                if (strObj == null)
                {
                    return null;
                }
                else
                {
                    return strObj.Value;
                }
            }
            /// <summary>
            /// 修改指定的XML文件钟add的值
            /// </summary>
            /// <param name="XmlFilePath">文件路径</param>
            /// <param name="Iskey">标签内key的值</param>
            /// <param name="Isvalue">即将被修改的标签内Isvalue的值</param>
            public void ModifyXmlFile(string XmlFilePath, string Iskey, string Isvalue)
            {
                XmlDocument doc = new XmlDocument();
                doc.Load(XmlFilePath);
                XmlNodeList nodes = doc.GetElementsByTagName("add");
                XmlAttribute att;
                for (int i = 0; i < nodes.Count; i++)
                {
                    //获得将当前元素的key属性  
                    att = nodes[i].Attributes["key"];
                    //根据元素的第一个属性来判断当前的元素是不是目标元素  
                    if (att.Value == Iskey)
                    {
                        //对目标元素中的第二个属性赋值  
                        att = nodes[i].Attributes["value"];
                        att.Value = Isvalue;
                        break;
                    }
                }
                //保存上面的修改  
                doc.Save(XmlFilePath);
            }
        }
    }
  • 相关阅读:
    Effective Java 第三版——72. 赞成使用标准异常
    Effective Java 第三版——71. 避免不必要地使用检查异常
    Effective Java 第三版——70. 对可恢复条件使用检查异常,对编程错误使用运行时异常
    Effective Java 第三版——69. 仅在发生异常的条件下使用异常
    Effective Java 第三版——68. 遵守普遍接受的命名约定
    Effective Java 第三版——67. 明智谨慎地进行优化
    Effective Java 第三版——66. 明智谨慎地使用本地方法
    Effective Java 第三版——65. 接口优于反射
    Effective Java 第三版——64. 通过对象的接口引用对象
    Effective Java 第三版——63. 注意字符串连接的性能
  • 原文地址:https://www.cnblogs.com/wskxy/p/9543768.html
Copyright © 2011-2022 走看看