【问题标题】:XML or INI files for storage? [closed]用于存储的 XML 或 INI 文件? [关闭]
【发布时间】:2014-02-26 17:17:23
【问题描述】:

存储值列表以供在我的程序中使用并允许用户更改它们的最佳方式是什么? XML 文件或 INI 文件,为什么?

如果您有更好的建议,欢迎您。

编辑:为了得到最合适的答案,这里有一些细节。但是,答案可以帮助其他用户,因为自定义详细信息仅作为 cmets 编写。

我有一个元素集合,每个元素都标有“真”或“假”值。
在我的程序中,我只想使用列表中用“真”值签名的元素。

我只能使用带有“True”元素的 Enum,但我希望用户通过将 false 更改为 true 来选择他想要的元素,反之亦然。

但是,我不希望他在每次执行中都选择所需的元素。这就是为什么我考虑使用可以根据用户偏好方便更改的文件的原因。

【问题讨论】:

  • 请定义“最佳”。
  • 值列表是否固定?
  • @PatrickHofman,误解了你的意思。
  • 你有一个永远不会改变的值列表?例如,编程语言“c#”、“vb.net”、“c++”的列表。或者它会改变,所以人的名字。
  • @PatrickHofman,正如我描述的目的,检查“false”和“true”的验证比直接元素名称更容易。这就是为什么不会更改列表的原因,只是可以仔细更改每个元素的适当值。谢谢

标签: c# xml ini


【解决方案1】:

在我看来有很多选择,但如果不是很有经验,你应该尽可能简单。

一种方法是使用您可以通过项目本身生成的设置。

只需在解决方案资源管理器中单击Add > New Item 将设置文件添加到您的项目,然后选择Settings File

This 是一篇关于将列表添加到设置文件的有用文章。


在您的情况下,您也可以选择string 设置。只需将整数值保存到 string 使用:

Properties.Settings.Default.SettingX = string.Join(",", array);

用这个把它们读回来:

string[] list = Properties.Settings.Default.SettingX.Split(',');

【讨论】:

  • 霍夫曼,用户可以更改设置值吗?怎么样?
  • 他们可以通过您的用户界面进行更改。如果您希望用户手动更改“文本文件”,他们可以编辑您的程序自动生成的 user.config 文件。
  • 如果您真的希望用户手动更改它,设置文件可能不是最佳选择。更新您的问题,告诉您为什么想要这个以及用户将如何编辑它,以便我们提供更好的答案。
  • 查看已编辑的问题,谢谢
  • 查看我的更新答案。
【解决方案2】:

我建议使用 .NET 默认方式,这肯定是 XML。

与 INI 格式相比,使用 XML 有一些优势:

  • 分层数据结构
  • 复杂的数据类型易于存储(序列化)
  • 您可以简单地使用 xsd 进行验证
  • XML 已标准化且面向未来

【讨论】:

    【解决方案3】:

    您可能应该使用app.config configuration 文件。

    它使用 XML 来存储设置,但框架会为您处理大部分繁琐的工作。

    如果您需要能够在运行时从应用程序更改设置,请查看Settings files

    【讨论】:

    • 用户可以更改设置值吗?如何?这个 app.config 存储在哪里?谢谢
    • 为什么在我的情况下配置文件比简单的 XML 更好? (请参阅已编辑的问题)
    【解决方案4】:

    最好地回答一个问题可能是一件大事。我认为这里有几个很好的解决方案,希望对您有所帮助。

    实际上,我开发了很多应用程序,所有这些应用程序都需要由最终用户配置。 在使用“xml”一段时间后,我将自己更改为仅由“propertyName”=“value”组成的简单 ini 文件。

    我写了一个简单的类来处理这类文件。用法很简单

    Settings.ConfigProperties cfProps = new Settings.ConfigProperties("c:\\test.ini");
    //if the file exists it will be read
    
    //to update or insert new values
    cfProps.UpdateValue("myNewProperty", "myValue");
    
    //to get a stored value
    String readValue = cfProps.ToString("myNewProperty");
    
    //to permanently write changes to the ini file
    cfProps.Save();
    

    代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.IO;
    namespace Settings
    {
        public class ConfigProperties
        {
            public class PropertyList<T> : List<ConfigProperty>
            {
                public ConfigProperty this[String propertyName]
                {
                    get
                    {
                        ConfigProperty ret = null;
                        foreach (ConfigProperty cp in this)
                        {
                            if (cp.Name == propertyName)
                            {
                                ret = cp;
                                break;
                            }
                        }
                        return ret;
                    }
                    set
                    {
                        ConfigProperty ret = null;
                        foreach (ConfigProperty cp in this)
                        {
                            if (cp.Name == propertyName)
                            {
                                ret = cp;
                                break;
                            }
                        }
                        value = ret;
                    }
                }
                public PropertyList()
                    : base()
                {
    
                }
    
                public void Add(String Name, String Value)
                {
                    ConfigProperty cp = new ConfigProperty();
                    cp.Name = Name;
                    cp.Value = Value;
                    this.Add(cp);
                }
            }
            public class ConfigProperty
            {
                public String Name { get; set; }
                public String Value { get; set; }
                public ConfigProperty()
                {
                    Name = "newPropertyName_" + DateTime.Now.Ticks.ToString();
                    Value = "";
                }
                public ConfigProperty(String name, String value)
                {
                    Name = name;
                    Value = value;
                }
            }
    
            public String FileName { get; set; }
            public PropertyList<ConfigProperty> CFCollection { get; private set; }
    
            public ConfigProperties()
                : this(AppDomain.CurrentDomain.BaseDirectory + "config.ini")
            {
            }
    
            public ConfigProperties(String fileName)
            {
                CFCollection = new PropertyList<ConfigProperty>();
                FileName = fileName;
                if (fileName != null && File.Exists(fileName))
                {
                    ReadFile();
                }
            }
    
            private void ReadFile()
            {
                if (File.Exists(FileName))
                {
                    CFCollection = new PropertyList<ConfigProperty>();
                    using (StreamReader sr = new StreamReader(FileName, Encoding.Default))
                    {
                        while (!sr.EndOfStream)
                        {
                            String line = sr.ReadLine();
                            if (!line.StartsWith("#"))
                            {
                                ConfigProperty cf = new ConfigProperty();
                                String tmp = "";
                                Char splitter = '=';
                                for (int i = 0; i < line.Length; i++)
                                {
                                    if (line[i] != splitter)
                                    {
                                        tmp += ((Char)line[i]).ToString();
                                    }
                                    else
                                    {
                                        cf.Name = tmp;
                                        tmp = "";
                                        splitter = '\n';
                                    }
                                }
                                cf.Value = tmp;
                                if (cf.Name.Length > 0)
                                {
                                    CFCollection.Add(cf);
                                }
                            }
                        }
    
                        sr.Close();
                    }
                }
            }
    
            private void SaveConfigProperty(ConfigProperty prop)
            {
                List<String> output = new List<String>();
                if (File.Exists(FileName))
                {
                    using (StreamReader sr = new StreamReader(FileName, Encoding.Default))
                    {
                        while (!sr.EndOfStream)
                        {
                            String line = sr.ReadLine();
                            if (line.StartsWith(prop.Name + "="))
                            {
                                output.Add(prop.Name + "=" + prop.Value);
                            }
                            else
                            {
                                output.Add(line);
                            }
                        }
                        sr.Close();
                    }
                }
    
                if (!output.Contains(prop.Name + "=" + prop.Value))
                {
                    output.Add(prop.Name + "=" + prop.Value);
                }
    
                StreamWriter sw = new StreamWriter(FileName, false, Encoding.Default);
    
                foreach (String s in output)
                {
                    sw.WriteLine(s);
                }
                sw.Close();
                sw.Dispose();
                GC.SuppressFinalize(sw);
                sw = null;
    
                output.Clear();
                output = null;
    
            }
    
            public void Save()
            {
                foreach (ConfigProperty cp in CFCollection)
                {
                    SaveConfigProperty(cp);
                }
            }
    
            public void UpdateValue(String propertyName, String propertyValue)
            {
                try
                {
                    IEnumerable<ConfigProperty> myProps = CFCollection.Where(cp => cp.Name.Equals(propertyName));
                    if (myProps.Count() == 1)
                    {
                        myProps.ElementAt(0).Value = propertyValue;
                    }
                    else if (myProps.Count() == 0)
                    {
                        CFCollection.Add(new ConfigProperty(propertyName, propertyValue));
                    }
                    else
                    {
                        throw new Exception("Can't find/set value for: " + propertyName);
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
    
            public String ToString(String propertyName)
            {
                try
                {
                    return CFCollection.Where(cp => cp.Name.Equals(propertyName)).First().Value;
                }
                catch (Exception ex)
                {
                    throw new Exception("Can't find/read value for: " +
                        propertyName, ex);
                }
            }
    
        }
    }
    

    【讨论】:

      【解决方案5】:

      我想推荐 JSON 格式

      • 可以人工阅读/编辑
      • 支持层次结构
      • 它不像 XML 那样复杂
      • 它可以像魅力一样使用(没有丑陋的ini解析)

      格式化文件的样子

      {"DevCommentVisibility":27,"CommentVisibility":1,"IssueStatusAfterCheckin":4,"Log":{"Debug":false,"Info":true,"Warn":true,"FileName":" d:\temp\2.log"},"语言":"en"}

      public static string Serialize(T pSettings)
      {
          return (new JavaScriptSerializer()).Serialize(pSettings);
      }
      
      public static T Load(string fileName)
      {
          T t = new T();
          if (File.Exists(fileName))
              try
              {
                  t = (new JavaScriptSerializer()).Deserialize<T>(File.ReadAllText(fileName));
                  var s = t as SettingsFoo;
                  if (s != null)
                      s.FileName = fileName;
              }
              catch (Exception ex)
              {
                  Trace.WriteLine(string.Format("failed to parse settings file {0}", fileName));
                  Trace.WriteLine(ex.Message);
              }
          else
          {
              Trace.WriteLine(string.Format("failed load settings '{0}' absolute '{1}'", fileName, Path.GetFullPath(fileName)));
              Save(t);
          }
          return t;
      }
      

      【讨论】:

      • 感谢您的回复。用户不能更改 XML 文件吗?
      • 是的,XML 也非常人性化..
      • @user3165438 实际上我更喜欢 JSON,因为它不需要结束标签(与 XML 相比)。我通常在小工具中使用 JSON。我有一些使用带有自定义部分处理程序的 app.config 或从 ConfigurationSection 派生的经验,并且可以说 Windows 应用程序的唯一优点是您可以使用 ProtectSection 方法保护任何部分。但是 JSON 中的密码可以使用 ProtectedData.Protect/Unprotect 方法处理。
      【解决方案6】:

      您可以使用简单的纯文件。

      List&lt;int&gt; list 保存到file.txt

      System.IO.File.WriteAllLines("file.txt", list.Select(v => v.ToString()).ToArray());
      

      加载中:

      List<int> loaded = System.IO.File.ReadAllLines("file.txt").Select(l => int.Parse(l)).ToList();
      

      使用扩展方法来设计更好的语法和正确的错误处理

      UPD:我可以提出的通用扩展方法(无异常处理):

      public static class MyExtensions
      {
          public static void SaveToFile<T>(this List<T> list, string filename)
          {
              System.IO.File.WriteAllLines(filename, list.Select(v => v.ToString()).ToArray());
          }
      
          public static void FillFromFile<T>(this List<T> list, string filename, Func<string, T> parser)
          {
              foreach (var line in System.IO.File.ReadAllLines(filename))
              {
                  T item = parser(line);
      
                  list.Add(item);
              }
          }
      }
      

      像这样使用它:

      List<int> list = new List<int>() { 0, 1, 2 };
      
      list.SaveToFile("numbers.txt");
      
      List<int> loaded = new List<int>();
      
      loaded.FillFromFile("numbers.txt", (l) => int.Parse(l));
      

      【讨论】:

      • 您能否指导我更多关于“使用扩展方法设计更好的语法和正确的错误处理”的信息,谢谢。
      • 如果您有一个string 对象列表怎么办?当项目包含换行符时,读取所有行可能会导致列表无效。
      • @PatrickHofman 没错,这个解决方案不适合存储带有换行符的字符串。虽然,如果需要,它可以改进。请注意,任何人类可读的解决方案都有这样的问题,这些问题通常可以通过“特殊”字符来解决
      • 没错,这就是为什么你应该尽可能恢复到标准。
      猜你喜欢
      • 2010-10-22
      • 2016-06-07
      • 2013-05-16
      • 1970-01-01
      • 1970-01-01
      • 2016-04-15
      • 2015-11-26
      • 2010-09-05
      相关资源
      最近更新 更多