简体   繁体   English

读/写一个INI文件

[英]Reading/writing an INI file

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# 是否有类似的东西?

Preface前言

Firstly, read this MSDN blog post on the limitations of INI files .首先,阅读这篇关于INI 文件限制的MSDN 博客文章。 If it suits your needs, read on.如果它适合您的需求,请继续阅读。

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, (ie Windows 98 - Windows 10).这是我编写的一个简洁的实现,使用了原始的 Windows P/Invoke,因此所有安装了 .NET 的 Windows 版本(即 Windows 98 - Windows 10)都支持它。 I hereby release it into the public domain - you're free to use it commercially without attribution.我特此将其发布到公共领域 - 您可以在没有署名的情况下自由地将其用于商业用途。

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:使用以下 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");

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 = MyIni.Read("DefaultVolume");
var HomePage = MyIni.Read("HomePage");

Optionally, you can set [Section] 's:或者,您可以设置[Section]的:

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!如有任何改进,请随时发表评论!

The creators of the .NET framework want you to use XML-based config files, rather than INI files. .NET 框架的创建者希望您使用基于 XML 的配置文件,而不是 INI 文件。 So no, there is no built-in mechanism for reading them.所以不,没有内置的机制来读取它们。

There are third party solutions available, though.不过,有第三方解决方案可用。

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.作者创建了一个 C# 类“Ini”,它公开了来自 KERNEL32.dll 的两个函数。 These functions are: WritePrivateProfileString and GetPrivateProfileString .这些函数是: WritePrivateProfileStringGetPrivateProfileString You will need two namespaces: System.Runtime.InteropServices and System.Text .您将需要两个命名空间: 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 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 .注意:如果您是从头开始,您可以阅读这篇MSDN 文章如何:将应用程序配置文件添加到 C# 项目 It's a better way for configuring your application.这是配置应用程序的更好方法。

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);
    }
}

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();
    }
}

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.我想介绍一个完全用 c# 创建的 IniParser 库,因此它不包含任何操作系统中的依赖项,这使其与 Mono 兼容。 Open Source with MIT license -so it can be used in any code.具有 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.很抱歉这个无耻的插件,但我希望它可以对任何重新访问此答案的人有所帮助。

If you only need read access and not write access and you are using the Microsoft.Extensions.Confiuration (comes bundled in by default with ASP.NET Core but works with regular programs too) you can use the NuGet package Microsoft.Extensions.Configuration.Ini to import ini files in to your configuration settings.如果您只需要读取访问权限而不需要写入访问权限,并且您正在使用Microsoft.Extensions.Confiuration (默认情况下与 ASP.NET Core 捆绑在一起,但也适用于常规程序),您可以使用 NuGet 包Microsoft.Extensions.Configuration.Ini将 ini 文件导入到您的配置设置中。

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

PeanutButter.INI is a Nuget-packaged class for INI files manipulation. PeanutButter.INI是用于 INI 文件操作的 Nuget 打包类。 It supports read/write, including comments – your comments are preserved on write.它支持读/写,包括评论——您的评论在写入时被保留。 It appears to be reasonably popular, is tested and easy to use.它似乎相当受欢迎,经过测试且易于使用。 It's also totally free and open-source.它也是完全免费和开源的。

Disclaimer: I am the author of PeanutButter.INI.免责声明:我是 PeanutButter.INI 的作者。

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

Try this method:试试这个方法:

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;
}

It creates the dictionary where the key is "-".它创建键为“-”的字典。 You can load it like this:你可以像这样加载它:

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

I'm late to join the party, but I had the same issue today and I've written the following implementation:我迟到了,但我今天遇到了同样的问题,我编写了以下实现:

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"];
}

It must be noted, that this implementation does not handle sections or properties which are not found.必须注意,此实现不处理未找到的部分或属性。 To achieve this, you should extend the Dictionary<,> -class to handle unfound keys.为此,您应该扩展Dictionary<,> -class 以处理未找到的键。


To serialize an instance of Dictionary<string, Dictionary<string, string>> to an .ini -file, I use the following code:要将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());

Usually, when you create applications using C# and the .NET framework, you will not use INI files.通常,当您使用 C# 和 .NET 框架创建应用程序时,您不会使用 INI 文件。 It is more common to store settings in an XML-based configuration file or in the registry.将设置存储在基于 XML 的配置文件或注册表中更为常见。 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.但是,如果您的软件与旧应用程序共享设置,则使用其配置文件可能会更容易,而不是在其他地方复制信息。

The .NET framework does not support the use of INI files directly. .NET 框架不支持直接使用 INI 文件。 However, you can use Windows API functions with Platform Invocation Services (P/Invoke) to write to and read from the files.但是,您可以使用 Windows API 函数和平台调用服务 (P/Invoke) 来写入和读取文件。 In this link we create a class that represents INI files and uses Windows API functions to manipulate them.在此链接中,我们创建了一个代表 INI 文件的类并使用 Windows API 函数来操作它们。 Please go through the following link.请通过以下链接。

Reading and Writing INI Files读取和写入 INI 文件

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.这具有用于获取部分/值的各种非常方便的重载,并且重量非常轻。

Here is my own version, using regular expressions.这是我自己的版本,使用正则表达式。 This code assumes that each section name is unique - if however this is not true - it makes sense to replace Dictionary with List.此代码假定每个部分名称都是唯一的 - 但是如果不是这样 - 用 List 替换 Dictionary 是有意义的。 This function supports .ini file commenting, starting from ';'该函数支持.ini文件注释,从';'开始character.特点。 Section starts normally [section], and key value pairs also comes normally "key = value".节正常开始[节],键值对也正常出现“键=值”。 Same assumption as for sections - key name is unique.与部分相同的假设 - 键名是唯一的。

/// <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;
}

If you don't need bells and whistles (ie sections) here's a one liner:如果您不需要花里胡哨(即部分),这里有一个衬里:

List<(string, string)> ini = File.ReadLines(filename)
  .Select(s => {
     var spl = s.Split('=', 2);
     return spl.Length == 2 ? (spl[0], spl[1]) : (s, "");
   })
   .Select(vt => (vt.Item1.Trim(), vt.Item2.Trim()))
   .Where(vt => vt.Item1 != "")
   .ToList();

To write:来写:

File.WriteAllLines(filename, ini.Select(vt => $"{vt.Item1}={vt.Item2}"));

(if you don't care about duplicates use .ToDictionary() instead of .ToList() for easier access) (如果您不关心重复项,请使用.ToDictionary()而不是.ToList()以便于访问)

Here is my class, works like a charm :这是我的课程,就像一个魅力:

public static class IniFileManager
{


    [DllImport("kernel32")]
    private static extern long WritePrivateProfileString(string section,
        string key, string val, string filePath);
    [DllImport("kernel32")]
    private static extern int GetPrivateProfileString(string section,
             string key, string def, StringBuilder retVal,
        int size, string filePath);
    [DllImport("kernel32.dll")]
    private static extern int GetPrivateProfileSection(string lpAppName,
             byte[] lpszReturnBuffer, int nSize, string lpFileName);


    /// <summary>
    /// Write Data to the INI File
    /// </summary>
    /// <PARAM name="Section"></PARAM>
    /// Section name
    /// <PARAM name="Key"></PARAM>
    /// Key Name
    /// <PARAM name="Value"></PARAM>
    /// Value Name
    public static void IniWriteValue(string sPath,string Section, string Key, string Value)
    {
        WritePrivateProfileString(Section, Key, Value, sPath);
    }

    /// <summary>
    /// Read Data Value From the Ini File
    /// </summary>
    /// <PARAM name="Section"></PARAM>
    /// <PARAM name="Key"></PARAM>
    /// <PARAM name="Path"></PARAM>
    /// <returns></returns>
    public static string IniReadValue(string sPath,string Section, string Key)
    {
        StringBuilder temp = new StringBuilder(255);
        int i = GetPrivateProfileString(Section, Key, "", temp,
                                        255, sPath);
        return temp.ToString();

    }

} }

The use is obviouse since its a static class, just call IniFileManager.IniWriteValue for readsing a section or IniFileManager.IniReadValue for reading a section.使用是显而易见的,因为它是一个静态类,只需调用 IniFileManager.IniWriteValue 读取部分或 IniFileManager.IniReadValue 读取部分。

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.您应该从 xml 文件读取和写入数据,因为您可以将整个对象保存到 xml,也可以从保存的 xml 填充对象。 It is better an easy to manipulate objects.最好是易于操作的对象。

Here is how to do it: Write Object Data to an XML File: https://msdn.microsoft.com/en-us/library/ms172873.aspx Read 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM