Lettura / scrittura di un file INI


263

Esiste una classe nel framework .NET in grado di leggere / scrivere file .ini standard:

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

Delphi ha il TIniFilecomponente e voglio sapere se esiste qualcosa di simile per C #?


RemObjects ha una libreria Delphi Prism chiamata ShineOn che fornisce una simile classe di file INI. Ma è necessario avere Delphi Prism per compilarlo per .NET dal sorgente in quanto non è ancora disponibile un assembly compilato. code.remobjects.com/p/shineon
Lex Li,

1
Ho avuto lo stesso problema e creato la mia libreria per l'analisi dei file ini: github.com/rickyah/ini-parser Spero che sia d'aiuto
Ricardo Amores,

5
Proprio come Ricky, ho deciso di fare la mia soluzione a questo. È disponibile su: github.com/MarioZ/MadMilkman.Ini
Mario Z,

Risposte:


185

I creatori del framework .NET 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.

Sono disponibili soluzioni di terze parti.


24
Anche se è vero che i file di configurazione XML sono la strada da percorrere, questa non è ancora una risposta alla domanda, o è VLQ solo per il collegamento.
Danny Beckett,

6
@aloneguid Direi che l'ampia serie di funzionalità disponibili ha effettivamente contribuito ai file di configurazione di .NET finendo per essere strani behemoth con molta magia in essi. Sono diventati "codice nel file di configurazione" e questo porta a molta complessità, comportamenti strani e rende più difficile la gestione della configurazione. (Ti guardo, "fornitori" di database e stringhe di connessione.) Quindi anche i file INI sono generalmente migliori per la modifica non manuale.
jpmc26,

1
mi piace il vecchio metodo (P / Inovke) e puoi usare unicode con il vecchio metodo come questo: File.WriteAllBytes (percorso, nuovo byte [] {0xFF, 0xFE});
sailfish009

2
Buon pacchetto ma potrebbe essere migliore. Non è in grado di analizzare un valore che contiene '=' O '\ n' completamente
Ahmad Behjati,

211

Prefazione

Innanzitutto, leggi questo post sul blog MSDN sui limiti 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 è supportato 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.csal 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;
        }

        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

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

Opzionalmente, 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!


4
Sono un po 'in ritardo, ma manca il GetSections()metodo.
stil

2
Forse un default più tradizionale sarebbe simile ai file .ini per applicazione (non per assembly) Path.GetFullPath(IniPath ?? Path.ChangeExtension(Application.ExecutablePath, ".ini")).
Eugene Ryabtsev,

3
Davvero fantastico ! Lo metti su github?
Emrys Myrooin,

2
@danny Beckett, ben fatto. Questo è quasi identico a quello che ho usato negli ultimi anni di .Net. Aggiornato dal vecchio codice anni fa.
Damian,

10
Vecchio ormai, e per quanto io stia rispettando Raymond Chen, molte delle limitazioni contenute in quell'articolo erano limitazioni della specifica libreria INI di Windows e non del formato INI stesso. Altri, come le autorizzazioni granulari, potrebbero essere facilmente evitati tramite più file. Una biblioteca INI ufficiale e modernizzata sarebbe benvenuta, anche oggi.
Joel Coehoorn,

68

Questo articolo su CodeProject " Una classe di gestione dei file INI che utilizza C # " dovrebbe essere di aiuto.

L'autore ha creato una classe C # "Ini" che espone due funzioni da KERNEL32.dll. Queste funzioni sono: WritePrivateProfileStringe GetPrivateProfileString. Avrai bisogno di due spazi dei nomi: System.Runtime.InteropServicese System.Text.

I passaggi per utilizzare la classe Ini

Nella definizione dello spazio dei nomi del progetto aggiungi

using INI;

Crea un INIFile come questo

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

Utilizzare IniWriteValueper scrivere un nuovo valore in una chiave specifica in una sezione o utilizzare IniReadValueper leggere un valore DA una chiave in una sezione specifica.

Nota: se si inizia da zero, è possibile leggere questo articolo MSDN : Procedura: aggiungere file di configurazione dell'applicazione a progetti C # . È un modo migliore per configurare l'applicazione.


1
Voglio leggere il file INI completo. Come fare lo stesso invece di leggere la sezione, chiave
venkat

questo ha funzionato per me e poi ha smesso di funzionare da un altro punto. Non
ho

1
Fai attenzione usando queste funzioni deprecate dell'API Win32. Maggiori informazioni: stackoverflow.com/questions/11451641/...
Pedro77

Ho usato questo approccio per un po ', ma i miglioramenti della sicurezza a partire da Win7 mi hanno praticamente ucciso. Puoi ancora utilizzare questo approccio, ma avrai archiviato il .ini in ProgramData e la tua app sarà letta / scritta lì.
Jess,

Non salvare i file ini di configurazione dell'applicazione in ProgramData. Non appartengono né al Registro né a ProgramData. I file di configurazione dovrebbero trovarsi nelle cartelle LocalApplicationData.
deceduto

47

Ho trovato questa semplice implementazione:

http://bytes.com/topic/net/insights/797169-reading-parsing-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);
    }
}

38
+1 per compensare sopra il downvote. Di cosa ti lamenti davvero? Ha detto di averlo trovato. Lo hai votato per non averne trovato uno con accessi generici e utilizzo di stringbuilder?
Tormod,

1
@Tormod: Vorrei poter sottovalutare il commento. È un forum tecnico quando votiamo sulle soluzioni, non sull'intento (ovviamente positivo). Se una soluzione pubblicata dallo stesso Knuth avesse dei difetti, sarebbe - e dovrebbe - essere indicata. Non importa se la soluzione è stata trovata o scritta dal poster.
ya23,

7
Penso che allunghi la definizione di "difetto". Se la soluzione non enfatizza le tue sensibilità, allora semplicemente non votare. Ho appena lasciato un messaggio dicendo che ho già annullato il suo voto negativo in modo che gli altri 7 ragazzi che hanno votato il mio commento non lo facciano da soli.
Tormod,

21

Il codice nella risposta di joerage è stimolante.

Sfortunatamente, cambia il carattere delle chiavi e non gestisce i commenti. Così 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 un po 'di LINQ, un dizionario di stringhe insensibile alle maiuscole nidificate per memorizzare sezioni, chiavi e valori e leggere il file in una volta sola.

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

4
e grazie per non mettere che catch (Exception ex) { throw ex; }lì dentro
Mark Schultheiss

1
Buona! Almeno alcune modifiche sono necessarie per funzionare meglio. Riga 16: ini [""] = currentSection; A: // ini [""] = currentSection; Questo deve essere rimosso poiché ogni volta che il primo elemento [0] sarà un segmento vuoto a causa di questa inizializzazione. Riga 36: currentSection [line.Substring (0, idx)] = line.Substring (idx + 1); A: currentSection [line.Substring (0, idx) .Trim ()] = line.Substring (idx + 1) .Trim (); Chiave e valori devono essere tagliati indipendentemente, non solo sulla linea di taglio. In INI come i file di configurazione di solito che aggiungono coppie K-> V tendono ad allineare questi uguali all'interno delle sezioni. Grazie!
LXSoft

Siamo stati molto tempo. Grazie mille per i tuoi suggerimenti. Hanno tutti un senso e merita questo codice per avere un buon aggiornamento.
Larry,

13

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 l'origine in GitHub ed è anche disponibile come pacchetto NuGet

È altamente configurabile e davvero semplice da usare .

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


4

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.Iniper importare i file ini nelle tue impostazioni di configurazione.

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

Solo per aggiungere che ottieni le chiavi conConfiguration["keyname"]
kofifus il

@scott il problema che sto riscontrando è per qualunque motivo IIS non lo riconosca quando l'app è in esecuzione. viene distribuito e lì, ma non viene consumato. Restituito HTTP 500.30 e il registro dell'app IIS indica "il file di configurazione non è stato trovato e non è facoltativo".
one.beat.consumer

3

Di solito, quando si creano applicazioni utilizzando C # e .NET Framework, non si useranno 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


4
Stai fuori dal registro! I dati di configurazione dell'applicazione non devono essere salvati nel registro.
decaduto

3

Se vuoi solo un semplice lettore senza sezioni e altre dll ecco la 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 (come vedi supporta il simbolo # per il commento di riga):

#command to run
command = php

#default script
action = index.php

#debug mode
#debug = true

#plain text mode
#plain = false

#icon = favico.ico

3

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

3

PeanutButter.INI è una classe impacchettata Nuget per la manipolazione di file INI. Supporta lettura / scrittura, inclusi i commenti: 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.


Potresti fornire un link alla documentazione di PeanutButter.INI?
Shroombaker,


3

Sono in ritardo per unirmi alla festa, ma ho avuto lo stesso problema oggi e ho scritto la 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"];
}

Va notato che questa implementazione non gestisce sezioni o proprietà che non sono state trovate. Per raggiungere questo obiettivo, è necessario estendere la Dictionary<,>classe per gestire le chiavi infondate.


Per serializzare un'istanza Dictionary<string, Dictionary<string, string>>in un .inifile, utilizzo 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());

2

Ini Parser è disponibile in CommonLibrary.NET

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


1
Nel caso in cui non sia ovvio guardando il livello superiore della libreria (non era ovvio per me!), La classe IniDcoument e altri sono in ComLib.IO.
Tim Keating

2
Per chiunque stia guardando questo percorso, CommonLibrary.NET non sembra seguire le convenzioni .INI. Utilizza i due punti ":" come delimitatore invece del segno di uguale e non gestisce i commenti (l'inizio di una riga con un punto e virgola o un cancelletto causerà il fallimento dell'analisi).
jmmr,

2

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 Dizionario con Elenco. Questa funzione supporta il commento di file .ini, a partire da ';' carattere. La sezione inizia normalmente [sezione] e anche le coppie di valori chiave vengono normalmente "chiave = valore". 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;
}

Quella funzione non funziona, per me: dimentica una sezione su due. Ho provato con e senza righe vuote prima di [Sezione].
come il

puoi copiare un esempio del tuo .ini che non funziona?
TarmoPikaro,

-3

Ecco la mia classe, funziona come un fascino:

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.


Questo approccio è già stato mostrato e spiegato in un'altra risposta . Cosa aggiunge la tua risposta che non è coperta da quella?
Palec,

Attenzione che funziona solo se il file .ini è salvato in UNICODE (16bit LE). Usa Notepad ++ per convertire il testo in Unicode, perché se lo salvi in ​​UTF-8 non funzionerà. Anche ANSI è accettabile, ma non puoi leggere lettere accentate
user2991288

-6

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 oggetti facilmente.

Ecco come farlo: Scrivi i dati degli oggetti in un file XML: https://msdn.microsoft.com/en-us/library/ms172873.aspx Leggi i dati degli oggetti da un file XML: https://msdn.microsoft. com / it-it / library / ms172872.aspx


1
I collegamenti a risorse esterne sono incoraggiati, ma per favore aggiungi un contesto attorno al collegamento in modo che i tuoi compagni utenti abbiano qualche idea di cosa sia e perché sia ​​lì. Cita sempre la parte più pertinente di un link importante, nel caso in cui il sito di destinazione non sia raggiungibile o sia permanentemente offline.
Davejal,

Credo che i titoli dei collegamenti siano molto chiari sui suoi riferimenti / contesto. Se pensi che non sia abbastanza sentiti libero di modificarlo.
Daniel,

1
Non affronta la domanda reale.
Erik Knowles,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.