.NET框架中是否有可以读/写标准.ini文件的类:
[Section]= ...
Delphi有TIniFile
组件,我想知道C#是否有类似内容?
首先,阅读这篇关于INI文件限制的 MSDN博客文章.如果它符合您的需求,请继续阅读.
这是我使用原始Windows P/Invoke编写的简洁实现,因此所有安装了.NET的Windows版本(即Windows 98 - Windows 10)都支持它.我特此将其发布到公共领域 - 您可以在没有归属的情况下自由使用它.
添加一个调用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; } } }
使用以下3种方法之一打开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");
要创建这样的文件:
[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");
要创建这样的文件:
[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");
如有任何改进,请随时评论!
.NET框架的创建者希望您使用基于XML的配置文件,而不是INI文件.所以不,没有内置的机制来阅读它们.
但是,还有第三方解决方案.
INI处理程序可以作为NuGet包获得,例如INI Parser.
你可以编写自己的INI处理程序,这是一种老式的,费力的方式.它使您可以更好地控制实现,您可以将其用于坏或好.参见例如使用C#,P/Invoke和Win32的INI文件处理类.
关于CodeProject的文章" 使用C#的INI文件处理类 "应该有所帮助.
作者创建了一个C#类"Ini",它暴露了KERNEL32.dll的两个函数.这些功能是: WritePrivateProfileString
和GetPrivateProfileString
.您将需要两个名称空间:System.Runtime.InteropServices
和System.Text
.
使用Ini类的步骤
在项目命名空间定义中添加
using INI;
像这样创建一个INIFile
INIFile ini = new INIFile("C:\\test.ini");
用于IniWriteValue
将新值写入节中的特定键或用于IniReadValue
从特定节中的键读取值.
注意:如果您从头开始,可以阅读此MSDN文章:如何:将应用程序配置文件添加到C#项目.这是配置应用程序的更好方法.
我找到了这个简单的实现:
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; } ////// Opens the INI file at the given path and enumerates the values in the IniParser. /// /// Full path to INI file. 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); } ////// Returns the value for the given section, key pair. /// /// Section name. /// Key name. public String GetSetting(String sectionName, String settingName) { SectionPair sectionPair; sectionPair.Section = sectionName.ToUpper(); sectionPair.Key = settingName.ToUpper(); return (String)keyPairs[sectionPair]; } ////// Enumerates all lines for given section. /// /// Section to enum. 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)); } ////// Adds or replaces a setting to the table to be saved. /// /// Section to add under. /// Key name to add. /// Value of key. 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); } ////// Adds or replaces a setting to the table to be saved with a null value. /// /// Section to add under. /// Key name to add. public void AddSetting(String sectionName, String settingName) { AddSetting(sectionName, settingName, null); } ////// Remove a setting. /// /// Section to add under. /// Key name to add. public void DeleteSetting(String sectionName, String settingName) { SectionPair sectionPair; sectionPair.Section = sectionName.ToUpper(); sectionPair.Key = settingName.ToUpper(); if (keyPairs.ContainsKey(sectionPair)) keyPairs.Remove(sectionPair); } ////// Save settings to new file. /// /// New file path. 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; } } ////// Save settings back to ini file. /// public void SaveSettings() { SaveSettings(iniFilePath); } }
joerage的答案中的代码鼓舞人心.
不幸的是,它改变了键的字符大小写并且不处理注释.所以我写了一些应该足够强大的东西来读取(仅)非常脏的INI文件,并允许按原样检索密钥.
它使用一些LINQ,一个嵌套的不区分大小写的字符串字典来存储节,键和值,并一次读取文件.
using System; using System.Collections.Generic; using System.IO; using System.Linq; class IniReader { Dictionary> ini = new Dictionary >(StringComparer.InvariantCultureIgnoreCase); public IniReader(string file) { var txt = File.ReadAllText(file); Dictionary currentSection = new Dictionary (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 (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#中完全创建的IniParser库,因此它在任何操作系统中都不包含任何依赖关系,这使得它与Mono兼容.使用MIT许可证的开源 - 因此它可以在任何代码中使用.
您可以在GitHub中查看源代码,它也可以作为NuGet包提供
它配置可靠,而且使用起来非常简单.
抱歉无耻的插件,但我希望它可以帮助任何人重新审视这个答案.