C# 读取/写入 INI 文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/217902/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Reading/writing an INI file
提问by zendar
Is there any class in the .NET framework that can read/write standard .ini files:
.NET 框架中是否有可以读/写标准 .ini 文件的类:
[Section]
<keyname>=<value>
...
Delphi has the TIniFile
component and I want to know if there is anything similar for C#?
Delphi有TIniFile
组件,我想知道C#是否有类似的东西?
采纳答案by David Arno
The creators of the .NET framework want you to use XML-based config files, rather than INI files. So no, there is no built-in mechanism for reading them.
.NET 框架的创建者希望您使用基于 XML 的配置文件,而不是 INI 文件。所以不,没有内置的机制来读取它们。
There are third party solutions available, though.
不过,有第三方解决方案可用。
- INI handlers can be obtained as NuGet packages, such as INI Parser.
- You can write your own INI handler, which is the old-school, laborious way. It gives you more control over the implementation, which you can use for bad or good. See e.g. an INI file handling class using C#, P/Invoke and Win32.
- INI 处理程序可以作为NuGet 包获得,例如INI Parser。
- 您可以编写自己的 INI 处理程序,这是老派的、费力的方法。它使您可以更好地控制实现,您可以将其用于好坏。参见例如使用 C#、P/Invoke 和 Win32 的 INI 文件处理类。
回答by splattne
This article on CodeProject "An INI file handling class using C#" should help.
CodeProject 上的这篇文章“使用 C# 的 INI 文件处理类”应该会有所帮助。
The author created a C# class "Ini" which exposes two functions from KERNEL32.dll. These functions are: WritePrivateProfileString
and GetPrivateProfileString
. You will need two namespaces: System.Runtime.InteropServices
and System.Text
.
作者创建了一个 C# 类“Ini”,它公开了来自 KERNEL32.dll 的两个函数。这些函数是: WritePrivateProfileString
和GetPrivateProfileString
。您将需要两个命名空间:System.Runtime.InteropServices
和System.Text
.
Steps to use the Ini class
使用 Ini 类的步骤
In your project namespace definition add
在您的项目命名空间定义中添加
using INI;
Create a INIFile like this
像这样创建一个 INIFile
INIFile ini = new INIFile("C:\test.ini");
Use IniWriteValue
to write a new value to a specific key in a section or use IniReadValue
to read a value FROM a key in a specific Section.
用于IniWriteValue
将新值写入部分中的特定键或用于IniReadValue
从特定部分中的键读取值。
Note: if you're beginning from scratch, you could read this MSDN article: How to: Add Application Configuration Files to C# Projects. It's a better way for configuring your application.
注意:如果您是从头开始,您可以阅读这篇MSDN 文章:如何:将应用程序配置文件添加到 C# 项目。这是配置应用程序的更好方法。
回答by james
There is an Ini Parser available in CommonLibrary.NET
CommonLibrary.NET 中有一个可用的 Ini 解析器
This has various very convenient overloads for getting sections/values and is very light weight.
这具有用于获取部分/值的各种非常方便的重载,并且重量非常轻。
回答by joerage
I found this simple implementation:
我发现了这个简单的实现:
http://bytes.com/topic/net/insights/797169-reading-parsing-ini-file-c
http://bytes.com/topic/net/insights/797169-reading-parsing-ini-file-c
Works well for what I need.
非常适合我的需要。
Here is how you use it:
以下是您如何使用它:
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();
}
}
Here is the code:
这是代码:
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);
}
}
回答by Unknown
Usually, when you create applications using C# and the .NET framework, you will not use INI files. It is more common to store settings in an XML-based configuration file or in the registry. However, if your software shares settings with a legacy application it may be easier to use its configuration file, rather than duplicating the information elsewhere.
通常,当您使用 C# 和 .NET 框架创建应用程序时,您不会使用 INI 文件。将设置存储在基于 XML 的配置文件或注册表中更为常见。但是,如果您的软件与旧应用程序共享设置,则使用其配置文件可能会更容易,而不是在其他地方复制信息。
The .NET framework does not support the use of INI files directly. However, you can use Windows API functions with Platform Invocation Services (P/Invoke) to write to and read from the files. In this link we create a class that represents INI files and uses Windows API functions to manipulate them. Please go through the following link.
.NET 框架不支持直接使用 INI 文件。但是,您可以使用 Windows API 函数和平台调用服务 (P/Invoke) 来写入和读取文件。在此链接中,我们创建了一个代表 INI 文件的类并使用 Windows API 函数来操作它们。请通过以下链接。
回答by Danny Beckett
Preface
前言
Firstly, read this MSDN blog post on the limitations of INI files. If it suits your needs, read on.
首先,阅读这篇关于INI 文件限制的MSDN 博客文章。如果它适合您的需求,请继续阅读。
This is a concise implementation I wrote, utilising the original Windows P/Invoke, so it is supported by all versions of Windows with .NET installed, (i.e. Windows 98 - Windows 10). I hereby release it into the public domain - you're free to use it commercially without attribution.
这是我编写的一个简洁的实现,使用了原始的 Windows P/Invoke,因此所有安装了 .NET 的 Windows 版本(即 Windows 98 - Windows 10)都支持它。我特此将其发布到公共领域 - 您可以在没有署名的情况下自由地将其用于商业用途。
The tiny class
小班级
Add a new class called IniFile.cs
to your project:
添加一个新的类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;
}
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;
}
}
}
How to use it
如何使用它
Open the INI file in one of the 3 following ways:
通过以下三种方式之一打开 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");
You can write some values like so:
你可以像这样写一些值:
MyIni.Write("DefaultVolume", "100");
MyIni.Write("HomePage", "http://www.google.com");
To create a file like this:
要创建这样的文件:
[MyProg]
DefaultVolume=100
HomePage=http://www.google.com
To read the values out of the INI file:
要从 INI 文件中读取值:
var DefaultVolume = IniFile.Read("DefaultVolume");
var HomePage = IniFile.Read("HomePage");
Optionally, you can set [Section]
's:
或者,您可以设置[Section]
's:
MyIni.Write("DefaultVolume", "100", "Audio");
MyIni.Write("HomePage", "http://www.google.com", "Web");
To create a file like this:
要创建这样的文件:
[Audio]
DefaultVolume=100
[Web]
HomePage=http://www.google.com
You can also check for the existence of a key like so:
您还可以像这样检查密钥是否存在:
if(!MyIni.KeyExists("DefaultVolume", "Audio"))
{
MyIni.Write("DefaultVolume", "100", "Audio");
}
You can delete a key like so:
您可以像这样删除一个键:
MyIni.DeleteKey("DefaultVolume", "Audio");
You can also delete a whole section (including all keys) like so:
您还可以删除整个部分(包括所有键),如下所示:
MyIni.DeleteSection("Web");
Please feel free to comment with any improvements!
如有任何改进,请随时发表评论!
回答by Larry
The code in joerage's answer is inspiring.
joerage 的回答中的代码是鼓舞人心的。
Unfortunately, it changes the character casing of the keys and does not handle comments. So I wrote something that should be robust enough to read (only) very dirty INI files and allows to retrieve keys as they are.
不幸的是,它改变了键的字符大小写并且不处理注释。所以我写了一些应该足够健壮的东西来读取(只)非常脏的 INI 文件,并允许按原样检索密钥。
It uses some LINQ, a nested case insensitive string dictionary to store sections, keys and values, and read the file in one go.
它使用一些 LINQ,一个嵌套的不区分大小写的字符串字典来存储部分、键和值,并一次性读取文件。
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();
}
}
回答by Ricardo Amores
I want to introduce an IniParser library I've created completely in c#, so it contains no dependencies in any OS, which makes it Mono compatible. Open Source with MIT license -so it can be used in any code.
我想介绍一个完全用 c# 创建的 IniParser 库,因此它不包含任何操作系统中的依赖项,这使其与 Mono 兼容。具有 MIT 许可证的开源 - 因此它可以在任何代码中使用。
You can check out the source in GitHub, and it is also available as a NuGet package
您可以在 GitHub 中查看源代码,它也可以作为 NuGet 包提供
It's heavily configurable, and really simple to use.
Sorry for the shameless plug but I hope it can be of help of anyone revisiting this answer.
很抱歉这个无耻的插件,但我希望它可以对任何重新访问此答案的人有所帮助。
回答by Daniel
You should read and write data from xml files since you can save a whole object to xml and also you can populate a object from a saved xml. It is better an easy to manipulate objects.
您应该从 xml 文件读取和写入数据,因为您可以将整个对象保存到 xml,也可以从保存的 xml 填充对象。最好是易于操作的对象。
Here is how to do it: Write Object Data to an XML File: https://msdn.microsoft.com/en-us/library/ms172873.aspxRead Object Data from an XML File: https://msdn.microsoft.com/en-us/library/ms172872.aspx
操作方法如下: 将对象数据写入 XML 文件:https: //msdn.microsoft.com/en-us/library/ms172873.aspx从 XML 文件中读取对象数据:https: //msdn.microsoft。 com/en-us/library/ms172872.aspx
回答by BIOHAZARD
If you want just a simple reader without sections and any other dlls here is simple solution:
如果您只想要一个没有节和任何其他 dll 的简单阅读器,这里是一个简单的解决方案:
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;
}
}
}
Usage sample:
使用示例:
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");
Config file content meanwhile (as you see supports # symbol for line comment):
同时配置文件内容(如您所见,支持行注释的 # 符号):
#command to run
command = php
#default script
action = index.php
#debug mode
#debug = true
#plain text mode
#plain = false
#icon = favico.ico