• [WPF 学习] 19. 增量更新


    不管是ClickOnce发布还是生成单个文件的发布都是全量更新,当引用的nuget包较多的时候,重复上传和下载的内容就比较多,所以需要增量更新。

    一、在数据库增加一个表

    CREATE TABLE [dbo].[TApp](
    	[Version] [int] IDENTITY(1,1) NOT NULL,
    	[Data] [varbinary](max) NOT NULL,
     CONSTRAINT [PK_TApp] PRIMARY KEY CLUSTERED 
    (
    	[Version] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
    ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
    GO
    

    就两列,Version列存放自增长版本号,Data列存放更新的数据。
    二、发布

            /// <summary>
            /// 发布
            /// </summary>
            /// <param name="path">发布的目标地址</param>
            /// <returns></returns>
            public static void Publish(string path)
            {
                if (!Directory.Exists(path))
                {
                    MessageBox.Show("目标地址不存在");
                    return;
                }
                var pathLast = Path.Combine(path, "Last");//保存最后一次发布的文件的文件夹
                if (!Directory.Exists(pathLast))
                {
                    Directory.CreateDirectory(pathLast);
                    PathCopy(path, pathLast);
                    MessageBox.Show("没有需要发布的内容");
                    return;
                }
    
                List<KeyValuePair<string, byte[]>> items = new List<KeyValuePair<string, byte[]>>();
                foreach (var fullFilename in Directory.GetFiles(path))
                {
                    var filename = Path.GetFileName(fullFilename);
                    var lastFilename = Path.Combine(pathLast, filename);
                    var buffer = File.ReadAllBytes(fullFilename);
                    if (File.Exists(lastFilename))
                    {
                        var lastBuffer = File.ReadAllBytes(lastFilename);
                        if (buffer.SequenceEqual(lastBuffer))
                            continue;
                    }
                    File.WriteAllBytes(lastFilename, buffer);
                    items.Add(new KeyValuePair<string, byte[]>(filename, buffer));
                }
                if (items.Count == 0)
                {
                    MessageBox.Show("没有需要发布的内容");
                    return;
                }
    
    
                #region 压缩一下
                var jsonString = JsonSerializer.Serialize(items);
                using MemoryStream instream = new MemoryStream(Encoding.UTF8.GetBytes(jsonString));
                using MemoryStream outstream = new MemoryStream();
                using DeflateStream defstream = new DeflateStream(outstream, CompressionMode.Compress);
                instream.CopyTo(defstream);
                defstream.Close();
                var data = outstream.ToArray();
                #endregion
    
    
    
    
    
                using SqlConnection cn = new SqlConnection(@"Data Source=.sqlexpress;initial Catalog=DBApp;integrated Security=True");
                var cmd = cn.CreateCommand();
                cmd.CommandText = "insert into tapp values (@Data)";
                cmd.Parameters.AddWithValue("@Data", data);
                cn.Open();
                cmd.ExecuteNonQuery();
    
                MessageBox.Show("发布成功");
            }
            /// <summary>
            /// 复制文件夹
            /// </summary>
            /// <param name="source"></param>
            /// <param name="destination"></param>
            private static void PathCopy(string source, string destination)
            {
                foreach (var filename in Directory.GetFiles(source))
                    File.Copy(filename, Path.Combine(destination, Path.GetFileName(filename)), true);
            }
    

    三、客户端更新

            public static void Update()
            {
                var currentPath = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
                var filenameVersion = Path.Combine(currentPath, "version.txt");
                int clientVersion = 0;
                if (File.Exists(filenameVersion))
                    clientVersion = int.Parse(File.ReadAllText(filenameVersion));
    
    
                using SqlConnection cn = new SqlConnection(@"Data Source=.sqlexpress;initial Catalog=DBApp;integrated Security=True");
                cn.Open();
                var cmd = cn.CreateCommand();
    
    
    
                #region 获取需要更新的内容
                List<KeyValuePair<int, byte[]>> kvs = new List<KeyValuePair<int, byte[]>>();
                cmd.CommandText = $"select * from tapp where version>{clientVersion}";
                var dr = cmd.ExecuteReader();
                while (dr.Read())
                    kvs.Add(new KeyValuePair<int, byte[]>(dr.GetInt32(0), (byte[])dr[1]));
                dr.Close();
                if (kvs.Count == 0)
                {
                    MessageBox.Show("没有需要更新的内容");
                    return;
                }
                #endregion
    
    
                var updatePath = Path.Combine(currentPath, "U" + DateTime.Now.Ticks);
                Directory.CreateDirectory(updatePath);
    
                foreach (var kv in kvs)
                {
                    #region 解压
                    using MemoryStream ms = new MemoryStream(kv.Value);
                    using MemoryStream ms2 = new MemoryStream();
                    using DeflateStream defStram = new DeflateStream(ms, CompressionMode.Decompress);
                    defStram.CopyTo(ms2);
                    defStram.Close();
                    var buffer = ms2.ToArray();
                    #endregion
    
                    var jsonString = Encoding.UTF8.GetString(buffer);
                    var items = JsonSerializer.Deserialize<List<KeyValuePair<string, byte[]>>>(jsonString);
                    foreach (var item in items)
                        File.WriteAllBytes(Path.Combine(updatePath, item.Key), item.Value);
                }
    
                File.WriteAllText(filenameVersion, kvs.Max(ii => ii.Key).ToString());//更新客户端版本号
    
    
                #region 生成并运行bat文件
                var batstr = $@"timeout /t 3
    taskkill /pid {Process.GetCurrentProcess().Id}
    copy {updatePath} {currentPath}
    del {updatePath} /Q
    rd {updatePath}
    {Process.GetCurrentProcess().MainModule.FileName}
    ";
                var filenameBat = Path.Combine(currentPath, "update.bat");
                File.WriteAllText(filenameBat, batstr);
                App.Current.Shutdown();
                Process.Start(filenameBat);
                #endregion
            }
    
    

    四、测试一下

    添加两个按钮,对应的click事件如下:

            private void BtnPublish_Click(object sender, RoutedEventArgs e)
            {
                Publish(@"D:TestHotConsoleApp1WpfUpdateinRelease
    et5.0-windowspublish");
            }
    
            private void BtnUpdate_Click(object sender, RoutedEventArgs e)
            {
                Update();
            }
    

    最后就是vs发布、单击发布按钮、单击更新按钮...

  • 相关阅读:
    mysql缓存
    复杂映射
    SQL 映射的 XML 文件
    xml配置文件
    从xml中构建sqlSessionFactory
    eclipse使用时jar不在libraries
    去掉不用的工作空间
    javac找不到或无法加载主类 com.sun.tools.javac.Main,
    文本,布局,样式
    (常用)re模块
  • 原文地址:https://www.cnblogs.com/catzhou/p/15161117.html
Copyright © 2020-2023  润新知