Lettura / scrittura di un file INI

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

[Section] = ... 

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

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

    Esistono tuttavia soluzioni di terze parti.

    • I gestori INI possono essere ottenuti come pacchetti NuGet , come INI Parser .
    • Puoi scrivere il tuo gestore INI, che è la vecchia scuola, un modo laborioso. Ti dà più controllo sull’implementazione, che puoi usare per il male o il bene. Vedi ad esempio una class di gestione file INI usando C #, P / Invoke e Win32 .

    Prefazione

    Innanzitutto, leggi questo post del blog MSDN sulle limitazioni dei file INI . Se è adatto alle 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 installate, (cioè Windows 98 – Windows 10). Con la presente la rendo di pubblico dominio – sei libero di usarla commercialmente senza attribuzione.

    La piccola class

    Aggiungi una nuova class 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 seguenti 3 modi:

     // 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, è ansible 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 cancellare una chiave in questo modo:

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

    Puoi anche cancellare un’intera sezione (incluse tutte le chiavi) in questo modo:

     MyIni.DeleteSection("Web"); 

    Non esitate a commentare con eventuali miglioramenti!

    Questo articolo su CodeProject ” Una class di gestione dei file INI che utilizza C # ” dovrebbe aiutare.

    L’autore ha creato una class C # “Ini” che espone due funzioni da KERNEL32.dll. Queste funzioni sono: WritePrivateProfileString e GetPrivateProfileString . Avrai bisogno di due spazi dei nomi: System.Runtime.InteropServices e System.Text .

    Passi per utilizzare la class Ini

    Nella tua definizione del namespace del progetto add

     using INI; 

    Crea un INIFile come questo

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

    Utilizzare IniWriteValue per scrivere un nuovo valore su una chiave specifica in una sezione o utilizzare IniReadValue per leggere un valore da una chiave in una sezione specifica.

    Nota: se si inizia da zero, è ansible leggere questo articolo MSDN : Procedura: aggiungere i file di configurazione dell’applicazione ai progetti C # . È un modo migliore per configurare la tua applicazione.

    Ho trovato questa semplice implementazione:

    http://bytes.com/topic/net/insights/797169-reading-parsing-ini-file-c

    Funziona bene per quello di cui ho bisogno.

    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; } ///  /// Opens the INI file at the given path and enumerates the values in the IniParser. ///  /// Full path to INI file. 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); } ///  /// Returns the value for the given section, key pair. ///  /// Section name. /// Key name. public String GetSetting(String sectionName, String settingName) { SectionPair sectionPair; sectionPair.Section = sectionName.ToUpper(); sectionPair.Key = settingName.ToUpper(); return (String)keyPairs[sectionPair]; } ///  /// Enumerates all lines for given section. ///  /// Section to enum. 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)); } ///  /// Adds or replaces a setting to the table to be saved. ///  /// Section to add under. /// Key name to add. /// Value of key. 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); } ///  /// Adds or replaces a setting to the table to be saved with a null value. ///  /// Section to add under. /// Key name to add. public void AddSetting(String sectionName, String settingName) { AddSetting(sectionName, settingName, null); } ///  /// Remove a setting. ///  /// Section to add under. /// Key name to add. public void DeleteSetting(String sectionName, String settingName) { SectionPair sectionPair; sectionPair.Section = sectionName.ToUpper(); sectionPair.Key = settingName.ToUpper(); if (keyPairs.ContainsKey(sectionPair)) keyPairs.Remove(sectionPair); } ///  /// Save settings to new file. ///  /// New file path. 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; } } ///  /// Save settings back to ini file. ///  public void SaveSettings() { SaveSettings(iniFilePath); } } 

    Il codice nella risposta di Joerage è stimolante.

    Sfortunatamente, cambia l’involucro dei caratteri 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 alcuni LINQ, un dizionario di stringa insensibile al maiuscolo e nidificato 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> ini = new Dictionary>(StringComparer.InvariantCultureIgnoreCase); public IniReader(string file) { var txt = File.ReadAllText(file); Dictionary currentSection = new Dictionary(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(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 alcun sistema operativo, il che rende Mono compatibile. Open Source con licenza MIT -so può essere utilizzato in qualsiasi codice.

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

    È altamente configurabile e molto semplice da usare .

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

    È ansible utilizzare SharpConfig per leggere file .cfg e / o .ini. È una libreria di configurazione facile da usare per .NET.

    Di solito, quando crei applicazioni usando C # e .NET framework, non utilizzerai i file INI. È più comune memorizzare 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 usare il suo file di configurazione, piuttosto che duplicare le informazioni altrove.

    Il framework .NET non supporta l’uso diretto dei file INI. Tuttavia, è ansible utilizzare le funzioni dell’API di Windows con Platform Invocation Services (P / Invoke) per scrivere e leggere dai file. In questo collegamento creiamo una class 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

    È 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 le espressioni regolari. Questo codice presuppone che ciascun nome di sezione sia univoco, ma se questo non è vero, è opportuno 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”. Stessa ipotesi delle sezioni: il nome della chiave è unico.

     ///  /// Loads .ini file into dictionary. ///  public static Dictionary> loadIni(String file) { Dictionary> d = new Dictionary>(); 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 lines = new Dictionary(); // 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 ParseIniDataWithSections(string[] iniData) { var dict = new Dictionary(); 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)); 

    Sono in ritardo per partecipare 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> ini = new Dictionary>(); 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]*\[(?[\w\-]+)\]", out Match m)) section = m.Groups["sec"].ToString(); else if (ln.match(@"^[ \t]*(?[\w\-]+)\=(?.*)", out m)) { if (!ini.ContainsKey(section)) ini[section] = new Dictionary(); ini[section][m.Groups["prop"].ToString()] = m.Groups["val"].ToString(); } } // access the ini file as follows: string content = ini["section"]["property"]; } 

    È necessario notare che questa implementazione non gestisce sezioni o proprietà che non sono state trovate. Per ottenere ciò, è necessario estendere il Dictionary< ,> -class per gestire le chiavi non trovate.


    Per serializzare un’istanza di Dictionary> in un file .ini , utilizzo il seguente codice:

     string targetpath = .........; Dictionary> 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()); 

    Se hai solo bisogno dell’accesso in lettura e non dell’accesso in scrittura e stai utilizzando Microsoft.Extensions.Confiuration (viene fornito in bundle per impostazione predefinita con ASP.NET Core ma funziona anche con programmi regolari) puoi utilizzare 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(); } 

    PeanutButter.INI è una class Nuget-packaged per la manipolazione dei file INI. Supporta la lettura / scrittura, inclusi i commenti: i tuoi commenti sono conservati in scrittura. Sembra essere ragionevolmente 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 altre DLL qui è 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  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; } } } 

    Campione 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, il contenuto del file di configurazione (come si vede 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 

    Dovresti leggere e scrivere dati da file xml dato che puoi salvare un intero object su xml e puoi anche popolare un object da un xml salvato. È meglio un object facile da manipolare.

    Ecco come fare: scrivere dati object in un file XML: https://msdn.microsoft.com/en-us/library/ms172873.aspx Leggi i dati object da un file XML: https://msdn.microsoft. com / it-it / library / ms172872.aspx