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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 18:33:40  来源:igfitidea点击:

Reading/writing an INI file

c#.netini

提问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 TIniFilecomponent 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.

不过,有第三方解决方案可用。

回答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: WritePrivateProfileStringand GetPrivateProfileString. You will need two namespaces: System.Runtime.InteropServicesand System.Text.

作者创建了一个 C# 类“Ini”,它公开了来自 KERNEL32.dll 的两个函数。这些函数是: WritePrivateProfileStringGetPrivateProfileString。您将需要两个命名空间:System.Runtime.InteropServicesSystem.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 IniWriteValueto write a new value to a specific key in a section or use IniReadValueto 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 函数来操作它们。请通过以下链接。

Reading and Writing INI Files

读取和写入 INI 文件

回答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.csto 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