Gibt es eine Klasse im .NET Framework, die Standard-INI-Dateien lesen / schreiben kann:
[Section]
<keyname>=<value>
...
Delphi hat die TIniFile
Komponente und ich möchte wissen, ob es etwas Ähnliches für C # gibt?
Gibt es eine Klasse im .NET Framework, die Standard-INI-Dateien lesen / schreiben kann:
[Section]
<keyname>=<value>
...
Delphi hat die TIniFile
Komponente und ich möchte wissen, ob es etwas Ähnliches für C # gibt?
Antworten:
Die Ersteller des .NET Frameworks möchten, dass Sie XML-basierte Konfigurationsdateien anstelle von INI-Dateien verwenden. Also nein, es gibt keinen eingebauten Mechanismus zum Lesen.
Es sind jedoch Lösungen von Drittanbietern verfügbar.
Lesen Sie zunächst diesen MSDN-Blogbeitrag über die Einschränkungen von INI-Dateien . Wenn es Ihren Bedürfnissen entspricht, lesen Sie weiter.
Dies ist eine prägnante Implementierung, die ich unter Verwendung des ursprünglichen Windows P / Invoke geschrieben habe. Sie wird daher von allen Windows-Versionen mit installiertem .NET (dh Windows 98 - Windows 10) unterstützt. Ich gebe es hiermit öffentlich zugänglich - Sie können es ohne Namensnennung kommerziell nutzen.
Fügen Sie IniFile.cs
Ihrem Projekt eine neue Klasse hinzu :
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;
}
}
}
Öffnen Sie die INI-Datei auf eine der folgenden drei Arten:
// 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");
Sie können einige Werte wie folgt schreiben:
MyIni.Write("DefaultVolume", "100");
MyIni.Write("HomePage", "http://www.google.com");
So erstellen Sie eine Datei wie folgt:
[MyProg]
DefaultVolume=100
HomePage=http://www.google.com
So lesen Sie die Werte aus der INI-Datei aus:
var DefaultVolume = IniFile.Read("DefaultVolume");
var HomePage = IniFile.Read("HomePage");
Optional können Sie Folgendes einstellen [Section]
:
MyIni.Write("DefaultVolume", "100", "Audio");
MyIni.Write("HomePage", "http://www.google.com", "Web");
So erstellen Sie eine Datei wie folgt:
[Audio]
DefaultVolume=100
[Web]
HomePage=http://www.google.com
Sie können auch prüfen, ob ein Schlüssel wie folgt vorhanden ist:
if(!MyIni.KeyExists("DefaultVolume", "Audio"))
{
MyIni.Write("DefaultVolume", "100", "Audio");
}
Sie können einen Schlüssel wie folgt löschen:
MyIni.DeleteKey("DefaultVolume", "Audio");
Sie können auch einen ganzen Abschnitt (einschließlich aller Schlüssel) wie folgt löschen:
MyIni.DeleteSection("Web");
Bitte zögern Sie nicht, mit Verbesserungen zu kommentieren!
GetSections()
Methode.
Path.GetFullPath(IniPath ?? Path.ChangeExtension(Application.ExecutablePath, ".ini"))
.
Dieser Artikel über CodeProject " Eine INI- Dateibehandlungsklasse mit C # " sollte helfen.
Der Autor hat eine C # -Klasse "Ini" erstellt, die zwei Funktionen aus KERNEL32.dll verfügbar macht. Diese Funktionen sind: WritePrivateProfileString
und GetPrivateProfileString
. Sie benötigen zwei Namespaces: System.Runtime.InteropServices
und System.Text
.
Schritte zur Verwendung der Ini-Klasse
Fügen Sie in Ihrer Projekt-Namespace-Definition hinzu
using INI;
Erstellen Sie eine INIFile wie diese
INIFile ini = new INIFile("C:\\test.ini");
Verwenden Sie IniWriteValue
diese Option , um einen neuen Wert in einen bestimmten Schlüssel in einem Abschnitt zu schreiben oder um IniReadValue
einen Wert aus einem Schlüssel in einem bestimmten Abschnitt zu lesen.
Hinweis: Wenn Sie bei Null anfangen, können Sie diesen MSDN-Artikel lesen : Gewusst wie: Hinzufügen von Anwendungskonfigurationsdateien zu C # -Projekten . Dies ist eine bessere Möglichkeit, Ihre Anwendung zu konfigurieren.
Ich fand diese einfache Implementierung:
http://bytes.com/topic/net/insights/797169-reading-parsing-ini-file-c
Funktioniert gut für das, was ich brauche.
So verwenden Sie es:
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();
}
}
Hier ist der 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);
}
}
Der Code in Joerages Antwort ist inspirierend.
Leider ändert es die Groß- und Kleinschreibung der Tasten und behandelt keine Kommentare. Also habe ich etwas geschrieben, das robust genug sein sollte, um (nur) sehr schmutzige INI-Dateien zu lesen und Schlüssel so abzurufen, wie sie sind.
Es verwendet etwas LINQ, ein verschachteltes String-Wörterbuch ohne Berücksichtigung der Groß- und Kleinschreibung, um Abschnitte, Schlüssel und Werte zu speichern und die Datei auf einmal zu lesen.
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();
}
}
catch (Exception ex) { throw ex; }
dort
Ich möchte eine IniParser-Bibliothek einführen, die ich vollständig in c # erstellt habe, damit sie in keinem Betriebssystem Abhängigkeiten enthält, wodurch sie Mono-kompatibel ist. Open Source mit MIT-Lizenz - kann also in jedem Code verwendet werden.
Sie können die Quelle in GitHub überprüfen und sie ist auch als NuGet-Paket verfügbar
Es ist stark konfigurierbar und sehr einfach zu bedienen .
Entschuldigen Sie den schamlosen Stecker, aber ich hoffe, er kann jedem helfen, der diese Antwort noch einmal überprüft.
Wenn Sie nur Lese- und keinen Schreibzugriff benötigen und das verwenden Microsoft.Extensions.Confiuration
(wird standardmäßig mit ASP.NET Core geliefert, funktioniert aber auch mit regulären Programmen), können Sie mit dem NuGet-Paket Microsoft.Extensions.Configuration.Ini
INI-Dateien in Ihre Konfigurationseinstellungen importieren.
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddIniFile("SomeConfig.ini", optional: false);
Configuration = builder.Build();
}
Configuration["keyname"]
Wenn Sie Anwendungen mit C # und dem .NET Framework erstellen, werden normalerweise keine INI-Dateien verwendet. Es ist üblicher, Einstellungen in einer XML-basierten Konfigurationsdatei oder in der Registrierung zu speichern. Wenn Ihre Software jedoch Einstellungen mit einer Legacy-Anwendung teilt, ist es möglicherweise einfacher, die Konfigurationsdatei zu verwenden, als die Informationen an anderer Stelle zu duplizieren.
Das .NET Framework unterstützt die direkte Verwendung von INI-Dateien nicht. Sie können jedoch Windows-API-Funktionen mit Platform Invocation Services (P / Invoke) verwenden, um in die Dateien zu schreiben und aus ihnen zu lesen. In diesem Link erstellen wir eine Klasse, die INI-Dateien darstellt und diese mithilfe von Windows-API-Funktionen bearbeitet. Bitte gehen Sie über den folgenden Link.
Wenn Sie nur einen einfachen Reader ohne Abschnitte und andere DLLs möchten, ist dies eine einfache Lösung:
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;
}
}
}
Anwendungsbeispiel:
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");
Konfigurieren Sie den Inhalt der Datei währenddessen (wie Sie sehen, unterstützt das Symbol # für den Zeilenkommentar):
#command to run
command = php
#default script
action = index.php
#debug mode
#debug = true
#plain text mode
#plain = false
#icon = favico.ico
Versuchen Sie diese Methode:
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;
}
Es wird das Wörterbuch erstellt, in dem der Schlüssel "-" lautet. Sie können es folgendermaßen laden:
var dict = ParseIniDataWithSections(File.ReadAllLines(fileName));
PeanutButter.INI ist eine Nuget-Paketklasse für die Manipulation von INI-Dateien. Es unterstützt Lesen / Schreiben, einschließlich Kommentare - Ihre Kommentare bleiben beim Schreiben erhalten. Es scheint ziemlich beliebt zu sein, ist getestet und einfach zu bedienen. Es ist auch völlig kostenlos und Open Source.
Haftungsausschluss: Ich bin der Autor von PeanutButter.INI.
Ich bin spät dran, um an der Party teilzunehmen, aber ich hatte heute das gleiche Problem und habe die folgende Implementierung geschrieben:
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"];
}
Es ist zu beachten, dass diese Implementierung keine Abschnitte oder Eigenschaften verarbeitet, die nicht gefunden wurden. Um dies zu erreichen, sollten Sie die Dictionary<,>
Klasse erweitern, um nicht gefundene Schlüssel zu verarbeiten.
Um eine Instanz von Dictionary<string, Dictionary<string, string>>
in eine .ini
-file zu serialisieren , verwende ich den folgenden Code:
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());
In CommonLibrary.NET ist ein Ini-Parser verfügbar
Dies hat verschiedene sehr bequeme Überlastungen zum Abrufen von Abschnitten / Werten und ist sehr leicht.
Hier ist meine eigene Version mit regulären Ausdrücken. In diesem Code wird davon ausgegangen, dass jeder Abschnittsname eindeutig ist. Wenn dies jedoch nicht der Fall ist, ist es sinnvoll, Dictionary durch List zu ersetzen. Diese Funktion unterstützt das Kommentieren von INI-Dateien ab ';' Charakter. Abschnitt beginnt normal [Abschnitt], und Schlüsselwertpaare kommen normalerweise auch "Schlüssel = Wert". Gleiche Annahme wie für Abschnitte - Schlüsselname ist eindeutig.
/// <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;
}
Hier ist meine Klasse, funktioniert wie ein Zauber:
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();
}
}}
Die Verwendung ist offensichtlich, da es sich um eine statische Klasse handelt. Rufen Sie einfach IniFileManager.IniWriteValue zum Lesen eines Abschnitts oder IniFileManager.IniReadValue zum Lesen eines Abschnitts auf.
Sie sollten Daten aus XML-Dateien lesen und schreiben, da Sie ein ganzes Objekt in XML speichern und ein Objekt aus einer gespeicherten XML-Datei füllen können. Es ist besser, Objekte einfach zu manipulieren.
So geht's: Objektdaten in eine XML-Datei schreiben: https://msdn.microsoft.com/en-us/library/ms172873.aspx Objektdaten aus einer XML-Datei lesen: https://msdn.microsoft. com / de-de / library / ms172872.aspx