Domanda

C'è qualche classe .NET framework in grado di leggere/scrivere standard .file ini:

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

Delphi ha il TIniFile componente e voglio sapere se c'è qualcosa di simile per C#?

È stato utile?

Soluzione

I creatori di .NET framework vogliono che tu utilizzi i file di configurazione basati su XML, piuttosto che i file INI. Quindi no, non esiste un meccanismo incorporato per leggerli.

Tuttavia, sono disponibili soluzioni di terze parti.

Altri suggerimenti

Prefazione

In primo luogo, leggi questo post sul blog MSDN su le limitazioni dei file INI . Se soddisfa le tue esigenze, continua a leggere.

Questa è un'implementazione concisa che ho scritto, utilizzando l'originale Windows P / Invoke, quindi è supportata da tutte le versioni di Windows con .NET installato (ovvero Windows 98 - Windows 10). Con la presente lo pubblico nel pubblico dominio - sei libero di usarlo commercialmente senza attribuzione.

La piccola classe

Aggiungi una nuova classe chiamata IniFile.cs al tuo progetto:

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

Come usarlo

Apri il file INI in uno dei 3 modi seguenti:

// 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");

Puoi scrivere alcuni valori in questo modo:

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

Per creare un file come questo:

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

Per leggere i valori dal file INI:

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

Facoltativamente, puoi impostare [Section]:

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

Per creare un file come questo:

[Audio]
DefaultVolume=100

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

Puoi anche verificare l'esistenza di una chiave in questo modo:

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

Puoi eliminare una chiave in questo modo:

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

Puoi anche eliminare un'intera sezione (comprese tutte le chiavi) in questo modo:

MyIni.DeleteSection("Web");

Non esitate a commentare con eventuali miglioramenti!

Questo articolo su CodeProject " Una classe di gestione dei file INI che utilizza C # <> quot!; dovrebbe aiutare.

L'autore ha creato una classe C # " Ini " che espone due funzioni da KERNEL32.dll. Queste funzioni sono: WritePrivateProfileString e GetPrivateProfileString. Sono necessari due spazi dei nomi: System.Runtime.InteropServices e System.Text.

Passaggi per utilizzare la classe Ini

Nella definizione dello spazio dei nomi del progetto aggiungere

using INI;

Crea un INIFile come questo

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

Usa IniWriteValue per scrivere un nuovo valore in una chiave specifica in una sezione o usa IniReadValue per leggere un valore DA una chiave in una sezione specifica.

Nota: se inizi da zero, puoi leggere questo articolo MSDN : Procedura: aggiungere file di configurazione dell'applicazione a progetti C # . È un modo migliore per configurare la tua applicazione.

Ho trovato questa semplice implementazione:

http://bytes.com/topic/ net / approfondimenti / 797.169-lettura-analisi-ini-file-c

Funziona bene per quello che mi serve.

Ecco come lo usi:

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

Ecco il codice:

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

Il codice nella risposta di joerage è stimolante.

Sfortunatamente, cambia il carattere delle chiavi e non gestisce i commenti. Quindi ho scritto qualcosa che dovrebbe essere abbastanza robusto da leggere (solo) file INI molto sporchi e permette di recuperare le chiavi così come sono.

Utilizza LINQ, un dizionario di stringhe insensibile alle maiuscole nidificate per memorizzare sezioni, chiavi e valori e leggere il file in una sola volta.

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

Voglio introdurre una libreria IniParser che ho creato completamente in c #, quindi non contiene dipendenze in nessun sistema operativo, il che lo rende compatibile con Mono. Open Source con licenza MIT, quindi può essere utilizzato in qualsiasi codice.

Puoi controllare la fonte in GitHub , ed è disponibile anche come pacchetto NuGet

È fortemente configurabile e veramente semplice da usare .

Ci scusiamo per la spina spudorata ma spero che possa essere d'aiuto a chiunque rivisiti questa risposta.

Di solito, quando crei applicazioni usando C # e .NET framework, non utilizzerai i file INI. È più comune archiviare le impostazioni in un file di configurazione basato su XML o nel registro. Tuttavia, se il tuo software condivide le impostazioni con un'applicazione legacy, potrebbe essere più semplice utilizzare il suo file di configurazione, piuttosto che duplicare le informazioni altrove.

Il framework .NET non supporta direttamente l'uso dei file INI. Tuttavia, è possibile utilizzare le funzioni API di Windows con Platform Invocation Services (P / Invoke) per scrivere e leggere dai file. In questo collegamento creiamo una classe che rappresenta i file INI e utilizza le funzioni dell'API di Windows per manipolarli. Si prega di passare attraverso il seguente link.

Lettura e scrittura di file INI

Sono in ritardo per partecipare alla festa, ma ho avuto lo stesso problema oggi e ho scritto il seguente implementazione:

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

Si deve notare, che questa implementazione non gestire sezioni o proprietà che non si trovano.Per raggiungere questo obiettivo, si dovrebbe estendere il Dictionary<,>-classe per gestire non trovata chiavi.


Per serializzare un esempio di Dictionary<string, Dictionary<string, string>> per un .ini-file, io uso il seguente codice:

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

È disponibile un Ini Parser in CommonLibrary.NET

Questo ha vari sovraccarichi molto convenienti per ottenere sezioni / valori ed è molto leggero.

Ecco la mia versione, usando espressioni regolari. Questo codice presuppone che il nome di ogni sezione sia univoco, se tuttavia non è vero, ha senso sostituire il Dizionario con Elenco. Questa funzione supporta il commento di file .ini, a partire da ';' personaggio. La sezione inizia normalmente [sezione] e anche le coppie di valori chiave vengono normalmente & Quot; chiave = valore & Quot ;. Stesso presupposto delle sezioni: il nome della chiave è univoco.

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

Prova questo metodo:

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

Crea il dizionario in cui la chiave è " - " ;. Puoi caricarlo in questo modo:

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

PeanutButter.INI è una classe impacchettata Nuget per la manipolazione di file INI. Supporta lettura / scrittura, inclusi i commenti & # 8211; i tuoi commenti vengono conservati in scrittura. Sembra essere abbastanza popolare, è testato e facile da usare. È anche totalmente gratuito e open-source.

Disclaimer: sono l'autore di PeanutButter.INI.

Se vuoi solo un semplice lettore senza sezioni e qualsiasi altra DLL, ecco una soluzione semplice:

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

Esempio di utilizzo:

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

Nel frattempo configura il contenuto del file di configurazione (come vedi supporta il simbolo # per il commento alla riga):

#command to run
command = php

#default script
action = index.php

#debug mode
#debug = true

#plain text mode
#plain = false

#icon = favico.ico

Se hai solo bisogno dell'accesso in lettura e non dell'accesso in scrittura e stai usando Microsoft.Extensions.Confiuration (viene fornito in bundle di default con ASP.NET Core ma funziona anche con programmi regolari) puoi usare il pacchetto NuGet Microsoft.Extensions.Configuration.Ini per importare file ini nelle impostazioni di configurazione.

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

Ecco la mia lezione, funziona come un incantesimo:

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

    }

}

L'uso è ovvio poiché è una classe statica, basta chiamare IniFileManager.IniWriteValue per leggere una sezione o IniFileManager.IniReadValue per leggere una sezione.

Dovresti leggere e scrivere dati da file xml poiché puoi salvare un intero oggetto in xml e puoi anche popolare un oggetto da un xml salvato. È meglio manipolare facilmente gli oggetti.

Ecco come farlo: Scrivere i dati oggetto in un file XML: https://msdn.microsoft.com/en -us / library / ms172873.aspx Leggere i dati oggetto da un file XML: https://msdn.microsoft.com/en -us / library / ms172872.aspx

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top