winform发布功能附加dll、db、xml、json等文件

文章讲述了在Winform应用中如何处理只读文件和可读写文件的发布与升级问题。对于只读文件,可以通过设置项目属性确保发布时包含文件。对于需读写的文件,提出了两种策略:一是程序首次运行时复制文件到本地,二是程序启动时动态创建文件并存储数据,避免升级覆盖。此外,还讨论了数据库文件的处理方式,以及如何处理数据库结构变更的情况,通过创建文件记录表和字段信息,在升级时对比并调整数据库结构。
摘要由CSDN通过智能技术生成

我们日常进行程序的更新升级可能会用到winform的发布功能,但有些文件可能会无法伴随着发布一同发布出去或者每次发布后文件的数据被覆盖,下面一起看一下怎么解决:

winform发布功能参考我另一篇文章https://blog.csdn.net/qq_39569480/article/details/127212245

仅限于读的文件:

这里我们以json文件为例,在项目中创建json文件,保存时以utf-8格式保存https://blog.csdn.net/qq_39569480/article/details/119610914 ,有一点需要注意这里创建的文件虽然可以同发布一同将文件发布出去,使用时仅限于读取,如果在程序运行过程中写入json文件,在下次程序升级时会覆盖原来写入的内容。
在这里插入图片描述
文件属性选择
在这里插入图片描述
右键项目属性——发布——应用程序文件,找到创建的文件选择包括,这样在发布时文件会同程序一同发布。
在这里插入图片描述

可读可写的文件

如果想发布可读可写的文件我们需要换一个思路,如果直接通过项目发布在程序运行时写入文件数据后,如果程序下次升级会重新覆盖这个文件之前写入的数据就会被覆盖掉。

第一种思路可以在程序中增加一个文件,在程序首次运行时检测本地有没有此文件如果没有则复制程序目录下的文件到本地指定文件夹,我们以后对这个文件进行操作。

第二种思路我们在程序启动时检测本地有无文件,没有文件则创建文件,动态的数据存在这个新创建的文件中,
每次读写这个新创建的文件

在程序的load事件中检测有无文件,没有则创建

if (!Directory.Exists(@"C:\SetUp")) Directory.CreateDirectory(@"C:\SetUp");
try
            {
                string FilePath = $@"C:\SetUp\appsettings.xml";
                XmlDocument xmlDoc = new XmlDocument();
                if (File.Exists(FilePath))
                {
                    xmlDoc.Load(FilePath);

                    XmlNode 二级 = xmlDoc.SelectSingleNode($"Configure/{InstrumentName}");
                    if (二级 == null)
                    {
                        XmlNode memberlist = xmlDoc.SelectSingleNode($"Configure");
                        XmlElement lq = xmlDoc.CreateElement(InstrumentName);
                        memberlist.AppendChild(lq);
                    }

                    //读取节点数据
                    if (二级 != null)
                    {
                        //二级.RemoveAll();
                        XmlNode node1 = xmlDoc.SelectSingleNode($"Configure/{InstrumentName}/SqlServerInstanceName");
                        if (node1 != null) 二级.RemoveChild(node1);
                        XmlNode node2 = xmlDoc.SelectSingleNode($"Configure/{InstrumentName}/SqlServerDataBaseName");
                        if (node2 != null) 二级.RemoveChild(node2); 
                    }

                    XmlElement el1 = xmlDoc.CreateElement("SqlServerInstanceName");
                    el1.InnerText = InstanceName;
                    XmlElement el2 = xmlDoc.CreateElement("SqlServerDataBaseName");
                    el2.InnerText = DataBaseName; 

                    XmlNode 二级节点 = xmlDoc.SelectSingleNode($"Configure/{InstrumentName}");
                    二级节点.AppendChild(el1); 二级节点.AppendChild(el2);  

                    xmlDoc.Save(FilePath);
                }
                else
                {
                    //加入XML的声明段落,Save方法不再xml上写出独立属性
                    xmlDoc.AppendChild(xmlDoc.CreateXmlDeclaration("1.0", "UTF-8", null));
                    //加入根元素 
                    XmlElement root = xmlDoc.CreateElement("Configure");
                    xmlDoc.AppendChild(root);

                    XmlElement memberlist = xmlDoc.CreateElement($"{InstrumentName}");

                    XmlElement el1 = xmlDoc.CreateElement("SqlServerInstanceName");
                    el1.InnerText = InstanceName;
                    XmlElement el2 = xmlDoc.CreateElement("SqlServerDataBaseName"); 

                    memberlist.AppendChild(el1); memberlist.AppendChild(el2);  

                    root.AppendChild(memberlist);
                    xmlDoc.Save(FilePath);
                }
                bool Result = ReadLocalSetUpFile();
                if (Result) MessageBox.Show("配置成功");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

db文件

数据库文件或者其它文件同上原理,我们先将文件放在项目中,属性选择始终复制,生成操作为内容,这样发布时会同程序一同发布
在这里插入图片描述
在这里插入图片描述
然后在程序运行时将文件拷贝至本地的指定路径

string ApplicationPath = Application.StartupPath;
string LocalDirectory=@"C:\";
string FilePath = $@"{LocalDirectory}MicrosoftStorage";

            if (!Directory.Exists(LocalDirectory)) Directory.CreateDirectory(LocalDirectory);
            if (!File.Exists(FilePath)) File.Copy($"{ApplicationPath}\\MicrosoftStorage", $@"{LocalDirectory}MicrosoftStorage", true);//允许覆盖目的地的同名文件

复制到指定文件夹后以后我们只需要读取本地的文件即可,这样每次发布升级就不会受影响

到这里可能大家还会有疑问,如果这个数据库以后有字段的新增修改怎么办呢?这里给大家提供一个思路:
首先我们可以在程序中创建一个文件,文件中记录所有表和字段的内容,程序每次升级时检测文件中的字段或表是否与数据库的表字段一致,不一致则新增
在这里插入图片描述
检测字段方法
可参考我另一篇文章检测sqlite字段是否存在https://blog.csdn.net/qq_39569480/article/details/128465934

private void CheckField()
        {
            try
            {
                List<FieldSetUpModel> Fields = new List<FieldSetUpModel>();
                using var streamReader = new StreamReader(@"Menu\Field.json", Encoding.UTF8);
                string FieldJson = streamReader.ReadToEnd();
                Fields = JsonConvert.DeserializeObject<List<FieldSetUpModel>>(FieldJson);

                FieldSetUpModel TableSetUp = new FieldSetUpModel();
                if (InstrumentName == "Excel文件") TableSetUp = Fields.Where(a => a.InstrumentName.Contains(InstrumentName) && a.Type == InstrumentType)?.FirstOrDefault();
                else TableSetUp = Fields.Where(a => a.InstrumentName.Contains(InstrumentName))?.FirstOrDefault();

                string[] FieldArray = TableSetUp.Fileds.Split(',');
                string TableName = TableSetUp.TableName;
                string LocalDB = $"{LocalDirectory}MicrosoftStorage";
                var (FieldCheckResult, FieldMsg) = _checkField.CheckFieldPresenceOrNot(TableName, FieldArray, _DB, LocalDB);
                if (!FieldCheckResult) MessageBox.Show("检查新增本地库表和字段时出现异常!请联系管理员");
            }
            catch (Exception e)
            {
                Log.Error($"检查新增本地数据库字段时失败:{e.Message + e.StackTrace + e.InnerException}");
                throw;
            }
        }
         public class FieldSetUpModel
    {
        public string InstrumentName { get; set; }
        public string Type { get; set; }
        public string TableName { get; set; }
        public string Fileds { get; set; }
    }
public (bool, string) CheckFieldPresenceOrNot(string TableName,string[] Field, DBConnHelper DB,string LocalDBPath) {
            using (IDbConnection db = DB.DBConnection("Sqlite", "", LocalDBPath, ""))
            {
                try
                {
                    string TableSql = $"select count(*) from sqlite_master where type='table' and name='{TableName}' ";
                    int ExistTable= db.ExecuteScalar<int>(TableSql);
                    if (ExistTable<1)
                    {//表不存在则新增表
                        List<string> NeedAddField = new List<string>();
                        for (int i = 0; i < Field.Length; i++)
                        {
                            NeedAddField.Add($"{Field[i]} TEXT");
                        }
                        string FieldStr = string.Join(",", NeedAddField);
                        string AddTableSql = $"create table {TableName}({FieldStr})";
                        db.Execute(AddTableSql);
                        string CreateAfter = $"select count(*) from sqlite_master where type='table' and name='{TableName}'";

                        bool TableAddResult = db.ExecuteScalar<int>(TableSql)>0;

                        if (!TableAddResult) return (false, $"添加本地库新表时失败,请联系管理员");
                        else return (true, "");
                    }

                    List<string> FailureField = new List<string>();
                    for (int i = 0; i < Field.Length; i++)
                    {
                        string Sql = $"PRAGMA  table_info({TableName})";
                        List<TableStructureModel> TableStructure= db.Query<TableStructureModel>(Sql).ToList();
                        bool Exist= TableStructure.Where(a=>a.name==Field[i]).ToList().Count()>0;
                        if (!Exist)
                        {//如果不存在则新增字段
                            string AddField = $"alter table {TableName} add column '{Field[i]}' TEXT";
                            bool EditResult= db.Execute(AddField)>0;
                            if (!EditResult)
                            {
                                FailureField.Add(Field[i]);
                            }
                        }
                    }
                    if (FailureField.Count>0)
                    {
                        string ErrorField= string.Join(",",FailureField);
                        return (false,$"添加本地库字段:{ErrorField}时失败,请联系管理员");
                    }
                    return (true,"");
                }
                catch (Exception ex)
                {
                    Log.Error($"检查新增本地数据表或库字段时失败:{ex.Message + ex.StackTrace + ex.InnerException}");
                    return (false,ex.Message);
                }
            }
        }
        public class TableStructureModel
    {
        public string cid { get; set; }
        public string name { get; set; }
        public string type { get; set; }
        public string notnull { get; set; }
        public string dflt_value { get; set; }
        public string pk { get; set; }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

香煎三文鱼

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值