读取/写入INI文件

.NET框架中是否有可以读写标准.ini文件的类:

[Section] <keyname>=<value> ... 

delphi有TIniFile组件,我想知道是否有什么类似的C#?

.NET框架的创build者希望您使用基于XML的configuration文件,而不是INI文件。 所以不,没有内置的机制来读取它们。

有第三方解决scheme,但。

  • INI处理程序可以作为NuGet程序包获得,例如INI Parser 。
  • 你可以编写你自己的INI处理程序,这是老派的,辛苦的方式。 它使您能够更好地控制实施,您可以使用这些实施不良或好的方法。 请参阅例如使用C#,P / Invoke和Win32的INI文件处理类 。

前言

首先阅读这篇关于INI文件限制的 MSDN博客文章。 如果它适合您的需求,请继续阅读。

这是我写的一个简洁的实现,利用原来的Windows P / Invoke,所以它支持所有版本的Windows与.NET安装,(即Windows 98 – Windows 10)。 我在此将其发布到公有领域 – 您可以自由使用它,而不需要任何权利。

小class

将一个名为IniFile.cs的新类添加到您的项目中:

 using System.IO; using System.Reflection; using System.Runtime.InteropServices; using System.Text; // Change this to match your program's normal namespace namespace MyProg { class IniFile // revision 11 { string Path; string EXE = Assembly.GetExecutingAssembly().GetName().Name; [DllImport("kernel32", CharSet = CharSet.Unicode)] static extern long WritePrivateProfileString(string Section, string Key, string Value, string FilePath); [DllImport("kernel32", CharSet = CharSet.Unicode)] static extern int GetPrivateProfileString(string Section, string Key, string Default, StringBuilder RetVal, int Size, string FilePath); public IniFile(string IniPath = null) { Path = new FileInfo(IniPath ?? EXE + ".ini").FullName.ToString(); } public string Read(string Key, string Section = null) { var RetVal = new StringBuilder(255); GetPrivateProfileString(Section ?? EXE, Key, "", RetVal, 255, Path); return RetVal.ToString(); } public void Write(string Key, string Value, string Section = null) { WritePrivateProfileString(Section ?? EXE, Key, Value, Path); } public void DeleteKey(string Key, string Section = null) { Write(Key, null, Section ?? EXE); } public void DeleteSection(string Section = null) { Write(null, null, Section ?? EXE); } public bool KeyExists(string Key, string Section = null) { return Read(Key, Section).Length > 0; } } } 

如何使用它

以以下三种方式之一打开INI文件:

 // Creates or loads an INI file in the same directory as your executable // named EXE.ini (where EXE is the name of your executable) var MyIni = new IniFile(); // Or specify a specific name in the current dir var MyIni = new IniFile("Settings.ini"); // Or specify a specific name in a specific dir var MyIni = new IniFile(@"C:\Settings.ini"); 

你可以这样写一些值:

 MyIni.Write("DefaultVolume", "100"); MyIni.Write("HomePage", "http://www.google.com"); 

要创build一个像这样的文件:

 [MyProg] DefaultVolume=100 HomePage=http://www.google.com 

要从INI文件中读取值:

 var DefaultVolume = IniFile.Read("DefaultVolume"); var HomePage = IniFile.Read("HomePage"); 

或者,您可以设置[Section]的:

 MyIni.Write("DefaultVolume", "100", "Audio"); MyIni.Write("HomePage", "http://www.google.com", "Web"); 

要创build一个像这样的文件:

 [Audio] DefaultVolume=100 [Web] HomePage=http://www.google.com 

你也可以检查一个键是否存在:

 if(!MyIni.KeyExists("DefaultVolume", "Audio")) { MyIni.Write("DefaultVolume", "100", "Audio"); } 

你可以像这样删除一个键:

 MyIni.DeleteKey("DefaultVolume", "Audio"); 

您也可以删除整个部分(包括所有键),如下所示:

 MyIni.DeleteSection("Web"); 

请随时评论任何改进!

这篇文章CodeProject“ 一个INI文件处理类使用C# ”应该有所帮助。

作者创build了一个C#类“Ini”,它公开了KERNEL32.dll中的两个函数。 这些函数是: WritePrivateProfileStringGetPrivateProfileString 。 您将需要两个名称空间: System.Runtime.InteropServicesSystem.Text

使用Ini类的步骤

在你的项目命名空间定义中添加

 using INI; 

像这样创build一个INIFile

 INIFile ini = new INIFile("C:\\test.ini"); 

使用IniWriteValue将新值写入节中的特定键或使用IniReadValue从特定节中的键中读取值。

注意:如果您从头开始,可以阅读本MSDN文章 : 如何:将应用程序configuration文件添加到C#项目 。 这是configuration应用程序的更好方法。

我发现这个简单的实现:

http://bytes.com/topic/net/insights/797169-reading-parsing-ini-file-c

适合我所需要的。

这里是你如何使用它:

 public class TestParser { public static void Main() { IniParser parser = new IniParser(@"C:\test.ini"); String newMessage; newMessage = parser.GetSetting("appsettings", "msgpart1"); newMessage += parser.GetSetting("appsettings", "msgpart2"); newMessage += parser.GetSetting("punctuation", "ex"); //Returns "Hello World!" Console.WriteLine(newMessage); Console.ReadLine(); } } 

这里是代码:

 using System; using System.IO; using System.Collections; public class IniParser { private Hashtable keyPairs = new Hashtable(); private String iniFilePath; private struct SectionPair { public String Section; public String Key; } /// <summary> /// Opens the INI file at the given path and enumerates the values in the IniParser. /// </summary> /// <param name="iniPath">Full path to INI file.</param> public IniParser(String iniPath) { TextReader iniFile = null; String strLine = null; String currentRoot = null; String[] keyPair = null; iniFilePath = iniPath; if (File.Exists(iniPath)) { try { iniFile = new StreamReader(iniPath); strLine = iniFile.ReadLine(); while (strLine != null) { strLine = strLine.Trim().ToUpper(); if (strLine != "") { if (strLine.StartsWith("[") && strLine.EndsWith("]")) { currentRoot = strLine.Substring(1, strLine.Length - 2); } else { keyPair = strLine.Split(new char[] { '=' }, 2); SectionPair sectionPair; String value = null; if (currentRoot == null) currentRoot = "ROOT"; sectionPair.Section = currentRoot; sectionPair.Key = keyPair[0]; if (keyPair.Length > 1) value = keyPair[1]; keyPairs.Add(sectionPair, value); } } strLine = iniFile.ReadLine(); } } catch (Exception ex) { throw ex; } finally { if (iniFile != null) iniFile.Close(); } } else throw new FileNotFoundException("Unable to locate " + iniPath); } /// <summary> /// Returns the value for the given section, key pair. /// </summary> /// <param name="sectionName">Section name.</param> /// <param name="settingName">Key name.</param> public String GetSetting(String sectionName, String settingName) { SectionPair sectionPair; sectionPair.Section = sectionName.ToUpper(); sectionPair.Key = settingName.ToUpper(); return (String)keyPairs[sectionPair]; } /// <summary> /// Enumerates all lines for given section. /// </summary> /// <param name="sectionName">Section to enum.</param> public String[] EnumSection(String sectionName) { ArrayList tmpArray = new ArrayList(); foreach (SectionPair pair in keyPairs.Keys) { if (pair.Section == sectionName.ToUpper()) tmpArray.Add(pair.Key); } return (String[])tmpArray.ToArray(typeof(String)); } /// <summary> /// Adds or replaces a setting to the table to be saved. /// </summary> /// <param name="sectionName">Section to add under.</param> /// <param name="settingName">Key name to add.</param> /// <param name="settingValue">Value of key.</param> public void AddSetting(String sectionName, String settingName, String settingValue) { SectionPair sectionPair; sectionPair.Section = sectionName.ToUpper(); sectionPair.Key = settingName.ToUpper(); if (keyPairs.ContainsKey(sectionPair)) keyPairs.Remove(sectionPair); keyPairs.Add(sectionPair, settingValue); } /// <summary> /// Adds or replaces a setting to the table to be saved with a null value. /// </summary> /// <param name="sectionName">Section to add under.</param> /// <param name="settingName">Key name to add.</param> public void AddSetting(String sectionName, String settingName) { AddSetting(sectionName, settingName, null); } /// <summary> /// Remove a setting. /// </summary> /// <param name="sectionName">Section to add under.</param> /// <param name="settingName">Key name to add.</param> public void DeleteSetting(String sectionName, String settingName) { SectionPair sectionPair; sectionPair.Section = sectionName.ToUpper(); sectionPair.Key = settingName.ToUpper(); if (keyPairs.ContainsKey(sectionPair)) keyPairs.Remove(sectionPair); } /// <summary> /// Save settings to new file. /// </summary> /// <param name="newFilePath">New file path.</param> public void SaveSettings(String newFilePath) { ArrayList sections = new ArrayList(); String tmpValue = ""; String strToSave = ""; foreach (SectionPair sectionPair in keyPairs.Keys) { if (!sections.Contains(sectionPair.Section)) sections.Add(sectionPair.Section); } foreach (String section in sections) { strToSave += ("[" + section + "]\r\n"); foreach (SectionPair sectionPair in keyPairs.Keys) { if (sectionPair.Section == section) { tmpValue = (String)keyPairs[sectionPair]; if (tmpValue != null) tmpValue = "=" + tmpValue; strToSave += (sectionPair.Key + tmpValue + "\r\n"); } } strToSave += "\r\n"; } try { TextWriter tw = new StreamWriter(newFilePath); tw.Write(strToSave); tw.Close(); } catch (Exception ex) { throw ex; } } /// <summary> /// Save settings back to ini file. /// </summary> public void SaveSettings() { SaveSettings(iniFilePath); } } 

joerage的答案中的代码是鼓舞人心的。

不幸的是,它改变了键的字符shell,并不处理注释。 所以我写了一些应该足够强大的东西来阅读(只)非常脏的INI文件,并允许按原样检索键。

它使用一些LINQ,一个嵌套的不区分大小写的string字典来存储部分,键和值,并一次读取文件。

 using System; using System.Collections.Generic; using System.IO; using System.Linq; class IniReader { Dictionary<string, Dictionary<string, string>> ini = new Dictionary<string, Dictionary<string, string>>(StringComparer.InvariantCultureIgnoreCase); public IniReader(string file) { var txt = File.ReadAllText(file); Dictionary<string, string> currentSection = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase); ini[""] = currentSection; foreach(var line in txt.Split(new[]{"\n"}, StringSplitOptions.RemoveEmptyEntries) .Where(t => !string.IsNullOrWhiteSpace(t)) .Select(t => t.Trim())) { if (line.StartsWith(";")) continue; if (line.StartsWith("[") && line.EndsWith("]")) { currentSection = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase); ini[line.Substring(1, line.LastIndexOf("]") - 1)] = currentSection; continue; } var idx = line.IndexOf("="); if (idx == -1) currentSection[line] = ""; else currentSection[line.Substring(0, idx)] = line.Substring(idx + 1); } } public string GetValue(string key) { return GetValue(key, "", ""); } public string GetValue(string key, string section) { return GetValue(key, section, ""); } public string GetValue(string key, string section, string @default) { if (!ini.ContainsKey(section)) return @default; if (!ini[section].ContainsKey(key)) return @default; return ini[section][key]; } public string[] GetKeys(string section) { if (!ini.ContainsKey(section)) return new string[0]; return ini[section].Keys.ToArray(); } public string[] GetSections() { return ini.Keys.Where(t => t != "").ToArray(); } } 

我想介绍一个完全在C#中创build的IniParser库,因此它在任何操作系统中都不包含任何依赖项,这使得它与Mono兼容。 开放源码与MIT许可证 – 所以它可以在任何代码中使用。

你可以在GitHub中查看源代码, 也可以作为NuGet包使用

它的configuration 非常重要,使用起来非常简单 。

抱歉无耻的插件,但我希望它可以帮助任何人重温这个答案。

您可以使用SharpConfig来读取.cfg和/或.ini文件。 这是一个易于使用的.NETconfiguration库。

通常,当您使用C#和.NET框架创build应用程序时,您将不会使用INI文件。 将设置存储在基于XML的configuration文件或registry中更为常见。 但是,如果您的软件与旧应用程序共享设置,则可能更容易使用其configuration文件,而不是在别处复制信息。

.NET框架不支持直接使用INI文件。 但是,您可以使用平台调用服务(P / Invoke)的Windows API函数来写入和读取文件。 在这个链接中,我们创build一个表示INI文件的类,并使用Windows API函数来操纵它们。 请通过以下链接。

读写INI文件

在CommonLibrary.NET中有一个Iniparsing器

这有各种非常方便的重载获取部分/值,是非常轻的重量。

如果你只想简单的阅读器没有部分和任何其他DLL这里是简单的解决scheme:

 using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Tool { public class Config { Dictionary <string, string> values; public Config (string path) { values = File.ReadLines(path) .Where(line => (!String.IsNullOrWhiteSpace(line) && !line.StartsWith("#"))) .Select(line => line.Split(new char[] { '=' }, 2, 0)) .ToDictionary(parts => parts[0].Trim(), parts => parts.Length>1?parts[1].Trim():null); } public string Value (string name, string value=null) { if (values!=null && values.ContainsKey(name)) { return values[name]; } return value; } } } 

用法示例:

  file = new Tool.Config (Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\config.ini"); command = file.Value ("command"); action = file.Value ("action"); string value; //second parameter is default value if no key found with this name value = file.Value("debug","true"); this.debug = (value.ToLower()=="true" || value== "1"); value = file.Value("plain", "false"); this.plain = (value.ToLower() == "true" || value == "1"); 

同时configuration文件内容(如您所看到的支持#行符号的注释):

 #command to run command = php #default script action = index.php #debug mode #debug = true #plain text mode #plain = false #icon = favico.ico 

试试这个方法:

 public static Dictionary<string, string> ParseIniDataWithSections(string[] iniData) { var dict = new Dictionary<string, string>(); var rows = iniData.Where(t => !String.IsNullOrEmpty(t.Trim()) && !t.StartsWith(";") && (t.Contains('[') || t.Contains('='))); if (rows == null || rows.Count() == 0) return dict; string section = ""; foreach (string row in rows) { string rw = row.TrimStart(); if (rw.StartsWith("[")) section = rw.TrimStart('[').TrimEnd(']'); else { int index = rw.IndexOf('='); dict[section + "-" + rw.Substring(0, index).Trim()] = rw.Substring(index+1).Trim().Trim('"'); } } return dict; } 

它创build密钥是“ – ”的字典。 你可以像这样加载它:

 var dict = ParseIniDataWithSections(File.ReadAllLines(fileName)); 

这是我自己的版本,使用正则expression式。 这段代码假设每个段的名字是唯一的 – 但是如果不是这样的话 – 用Listreplace字典是有意义的。 该function支持.ini文件注释,从';'开始 字符。 部分通常以[section]开始,而键值对通常也是“key = value”。 与部分相同的假设 – 键名是独一无二的。

 /// <summary> /// Loads .ini file into dictionary. /// </summary> public static Dictionary<String, Dictionary<String, String>> loadIni(String file) { Dictionary<String, Dictionary<String, String>> d = new Dictionary<string, Dictionary<string, string>>(); String ini = File.ReadAllText(file); // Remove comments, preserve linefeeds, if end-user needs to count line number. ini = Regex.Replace(ini, @"^\s*;.*$", "", RegexOptions.Multiline); // Pick up all lines from first section to another section foreach (Match m in Regex.Matches(ini, "(^|[\r\n])\\[([^\r\n]*)\\][\r\n]+(.*?)(\\[([^\r\n]*)\\][\r\n]+|$)", RegexOptions.Singleline)) { String sectionName = m.Groups[2].Value; Dictionary<String, String> lines = new Dictionary<String, String>(); // Pick up "key = value" kind of syntax. foreach (Match l in Regex.Matches(ini, @"^\s*(.*?)\s*=\s*(.*?)\s*$", RegexOptions.Multiline)) { String key = l.Groups[1].Value; String value = l.Groups[2].Value; // Open up quotation if any. value = Regex.Replace(value, "^\"(.*)\"$", "$1"); if (!lines.ContainsKey(key)) lines[key] = value; } if (!d.ContainsKey(sectionName)) d[sectionName] = lines; } return d; } 

PeanutButter.INI是一个用于INI文件操作的Nuget打包类。 它支持读/写,包括评论 – 你的评论保存在写。 这似乎是相当受欢迎,经过testing和易于使用。 它也是完全免费和开源的。

免责声明:我是PeanutButter.INI的作者。

如果您只需要读取访问权限而不是写入访问权限,并且您正在使用Microsoft.Extensions.Confiuration (默认情况下与ASP.NET Core捆绑在一起,但也可以与常规程序一起使用),则可以使用NuGet软件包Microsoft.Extensions.Configuration.Ini将ini文件导入到您的configuration设置中。

 public Startup(IHostingEnvironment env) { var builder = new ConfigurationBuilder() .SetBasePath(env.ContentRootPath) .AddIniFile("SomeConfig.ini", optional: false); Configuration = builder.Build(); } 

我迟到了,但是我今天遇到了同样的问题,我写了下面这段话:

 using System.Text.RegularExpressions; static bool match(this string str, string pat, out Match m) => (m = Regex.Match(str, pat, RegexOptions.IgnoreCase)).Success; static void Main() { Dictionary<string, Dictionary<string, string>> ini = new Dictionary<string, Dictionary<string, string>>(); string section = ""; foreach (string line in File.ReadAllLines(.........)) // read from file { string ln = (line.Contains('#') ? line.Remove(line.IndexOf('#')) : line).Trim(); if (ln.match(@"^[ \t]*\[(?<sec>[\w\-]+)\]", out Match m)) section = m.Groups["sec"].ToString(); else if (ln.match(@"^[ \t]*(?<prop>[\w\-]+)\=(?<val>.*)", out m)) { if (!ini.ContainsKey(section)) ini[section] = new Dictionary<string, string>(); ini[section][m.Groups["prop"].ToString()] = m.Groups["val"].ToString(); } } // access the ini file as follows: string content = ini["section"]["property"]; } 

必须注意的是,这个实现不处理没有find的部分或属性。 为了达到这个目的,你应该扩展Dictionary<,> -class来处理未被感染的键。


要将Dictionary<string, Dictionary<string, string>>的实例序列化为.ini文件,我使用下面的代码:

 string targetpath = .........; Dictionary<string, Dictionary<string, string>> ini = ........; StringBuilder sb = new StringBuilder(); foreach (string section in ini.Keys) { sb.AppendLine($"[{section}]"); foreach (string property in ini[section].Keys) sb.AppendLine($"{property}={ini[section][property]"); } File.WriteAllText(targetpath, sb.ToString()); 

您应该读取和写入xml文件的数据,因为您可以将整个对象保存到xml中,也可以从保存的xml中填充对象。 对物体进行操纵是一件好事。

下面是如何做到这一点:将对象数据写入XML文件: https : //msdn.microsoft.com/en-us/library/ms172873.aspx从XML文件读取对象数据: https : //msdn.microsoft。 COM / EN-US /库/ ms172872.aspx