Apakah ada kelas dalam kerangka .NET yang dapat membaca / menulis file .ini standar:
[Section]
<keyname>=<value>
...
Delphi memiliki TIniFile
komponen dan saya ingin tahu apakah ada yang serupa untuk C #?
Apakah ada kelas dalam kerangka .NET yang dapat membaca / menulis file .ini standar:
[Section]
<keyname>=<value>
...
Delphi memiliki TIniFile
komponen dan saya ingin tahu apakah ada yang serupa untuk C #?
Jawaban:
Pembuat kerangka .NET ingin Anda menggunakan file konfigurasi berbasis XML, bukan file INI. Jadi tidak, tidak ada mekanisme bawaan untuk membacanya.
Namun, ada solusi pihak ketiga.
Pertama, baca posting blog MSDN ini tentang batasan file INI . Jika sesuai dengan kebutuhan Anda, baca terus.
Ini adalah implementasi singkat yang saya tulis, menggunakan Windows P / Invoke asli, sehingga didukung oleh semua versi Windows dengan .NET yang diinstal, (yaitu Windows 98 - Windows 10). Saya dengan ini merilisnya ke domain publik - Anda bebas menggunakannya secara komersial tanpa atribusi.
Tambahkan kelas baru yang dipanggil IniFile.cs
ke proyek Anda:
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;
}
}
}
Buka file INI dengan salah satu dari 3 cara berikut:
// 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");
Anda dapat menulis beberapa nilai seperti:
MyIni.Write("DefaultVolume", "100");
MyIni.Write("HomePage", "http://www.google.com");
Untuk membuat file seperti ini:
[MyProg]
DefaultVolume=100
HomePage=http://www.google.com
Untuk membaca nilai dari file INI:
var DefaultVolume = IniFile.Read("DefaultVolume");
var HomePage = IniFile.Read("HomePage");
Secara opsional, Anda dapat mengatur [Section]
:
MyIni.Write("DefaultVolume", "100", "Audio");
MyIni.Write("HomePage", "http://www.google.com", "Web");
Untuk membuat file seperti ini:
[Audio]
DefaultVolume=100
[Web]
HomePage=http://www.google.com
Anda juga dapat memeriksa keberadaan kunci seperti:
if(!MyIni.KeyExists("DefaultVolume", "Audio"))
{
MyIni.Write("DefaultVolume", "100", "Audio");
}
Anda dapat menghapus kunci seperti:
MyIni.DeleteKey("DefaultVolume", "Audio");
Anda juga dapat menghapus seluruh bagian (termasuk semua kunci) seperti:
MyIni.DeleteSection("Web");
Jangan ragu untuk berkomentar dengan peningkatan apa pun!
GetSections()
metode yang hilang .
Path.GetFullPath(IniPath ?? Path.ChangeExtension(Application.ExecutablePath, ".ini"))
.
Artikel ini pada CodeProject " Kelas penanganan file INI menggunakan C # " akan membantu.
Penulis membuat kelas C # "Ini" yang memperlihatkan dua fungsi dari KERNEL32.dll. Fungsi-fungsi ini adalah: WritePrivateProfileString
dan GetPrivateProfileString
. Anda akan membutuhkan dua ruang nama: System.Runtime.InteropServices
dan System.Text
.
Langkah-langkah untuk menggunakan kelas Ini
Dalam proyek Anda tambahkan definisi namespace
using INI;
Buat INIFile seperti ini
INIFile ini = new INIFile("C:\\test.ini");
Gunakan IniWriteValue
untuk menulis nilai baru ke kunci tertentu di bagian atau gunakan IniReadValue
untuk membaca nilai DARI kunci di Bagian tertentu.
Catatan: jika Anda memulai dari awal, Anda bisa membaca artikel MSDN ini : Cara: Menambahkan File Konfigurasi Aplikasi ke Proyek C # . Ini cara yang lebih baik untuk mengonfigurasi aplikasi Anda.
Saya menemukan implementasi sederhana ini:
http://bytes.com/topic/net/insights/797169-reading-parsing-ini-file-c
Bekerja dengan baik untuk apa yang saya butuhkan.
Inilah cara Anda menggunakannya:
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();
}
}
Ini kodenya:
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);
}
}
Kode dalam jawaban joerage menginspirasi.
Sayangnya, itu mengubah casing karakter tombol dan tidak menangani komentar. Jadi saya menulis sesuatu yang harus cukup kuat untuk membaca (hanya) file INI yang sangat kotor dan memungkinkan untuk mengambil kunci apa adanya.
Ini menggunakan beberapa LINQ, kamus string tidak bersarang case untuk menyimpan bagian, kunci dan nilai, dan membaca file dalam sekali jalan.
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; }
ke sana
Saya ingin memperkenalkan pustaka IniParser yang saya buat sepenuhnya dalam c #, jadi tidak mengandung dependensi pada OS apa pun, yang membuatnya kompatibel dengan Mono. Open Source dengan lisensi MIT -jadi dapat digunakan dalam kode apa pun.
Anda dapat memeriksa sumbernya di GitHub , dan juga tersedia sebagai paket NuGet
Ini sangat dapat dikonfigurasi , dan sangat mudah digunakan .
Maaf untuk plug yang tidak tahu malu tapi saya harap ini bisa membantu siapa pun yang melihat kembali jawaban ini.
Jika Anda hanya perlu akses baca dan bukan akses tulis dan Anda menggunakan Microsoft.Extensions.Confiuration
(disertakan secara default dengan ASP.NET Core tetapi juga berfungsi dengan program reguler), Anda dapat menggunakan paket NuGet Microsoft.Extensions.Configuration.Ini
untuk mengimpor file ini ke pengaturan konfigurasi Anda.
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddIniFile("SomeConfig.ini", optional: false);
Configuration = builder.Build();
}
Configuration["keyname"]
Biasanya, saat Anda membuat aplikasi menggunakan C # dan framework .NET, Anda tidak akan menggunakan file INI. Lebih umum untuk menyimpan pengaturan dalam file konfigurasi berbasis XML atau dalam registri. Namun, jika perangkat lunak Anda berbagi pengaturan dengan aplikasi lawas, mungkin lebih mudah untuk menggunakan file konfigurasinya, daripada menduplikasi informasi di tempat lain.
Kerangka .NET tidak mendukung penggunaan file INI secara langsung. Namun, Anda dapat menggunakan fungsi Windows API dengan Platform Invocation Services (P / Invoke) untuk menulis dan membaca dari file. Di tautan ini kami membuat kelas yang mewakili file INI dan menggunakan fungsi Windows API untuk memanipulasinya. Silakan buka tautan berikut.
Jika Anda ingin hanya pembaca sederhana tanpa bagian dan dll lainnya di sini adalah solusi sederhana:
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;
}
}
}
Sampel penggunaan:
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");
Sementara itu konfigurasi file konten (seperti yang Anda lihat mendukung # simbol untuk komentar baris):
#command to run
command = php
#default script
action = index.php
#debug mode
#debug = true
#plain text mode
#plain = false
#icon = favico.ico
Coba metode ini:
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;
}
Itu menciptakan kamus di mana kuncinya adalah "-". Anda dapat memuatnya seperti ini:
var dict = ParseIniDataWithSections(File.ReadAllLines(fileName));
PeanutButter.INI adalah kelas Nuget-dikemas untuk file INI manipulasi. Ini mendukung baca / tulis, termasuk komentar - komentar Anda dipertahankan pada saat menulis. Tampaknya cukup populer, diuji dan mudah digunakan. Ini juga sepenuhnya gratis dan open-source.
Penafian: Saya adalah penulis PeanutButter.INI.
Saya terlambat untuk bergabung dengan pesta, tetapi saya memiliki masalah yang sama hari ini dan saya telah menulis implementasi berikut:
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"];
}
Harus dicatat, bahwa implementasi ini tidak menangani bagian atau properti yang tidak ditemukan. Untuk mencapai ini, Anda harus memperluas Dictionary<,>
-kelas untuk menangani kunci yang tidak berdasar.
Untuk membuat serial instance Dictionary<string, Dictionary<string, string>>
ke .ini
-file, saya menggunakan kode berikut:
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());
Ada Parser Ini tersedia di CommonLibrary.NET
Ini memiliki berbagai kelebihan yang sangat mudah untuk mendapatkan bagian / nilai dan sangat ringan.
Ini versi saya sendiri, menggunakan ekspresi reguler. Kode ini mengasumsikan bahwa setiap nama bagian adalah unik - jika bagaimanapun ini tidak benar - masuk akal untuk mengganti Kamus dengan Daftar. Fungsi ini mendukung komentar file .ini, mulai dari ';' karakter. Bagian dimulai secara normal [bagian], dan pasangan nilai kunci juga datang secara normal "key = value". Asumsi yang sama seperti untuk bagian - nama kunci unik.
/// <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;
}
Inilah kelas saya, bekerja seperti pesona:
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();
}
}
Penggunaannya sudah usang karena kelasnya statis, cukup panggil IniFileManager.IniWriteValue untuk membaca bagian atau IniFileManager.IniReadValue untuk membaca bagian.
Anda harus membaca dan menulis data dari file xml karena Anda dapat menyimpan seluruh objek ke xml dan juga Anda dapat mengisi objek dari xml yang disimpan. Lebih baik mudah memanipulasi objek.
Berikut ini cara melakukannya: Menulis Data Objek ke File XML: https://msdn.microsoft.com/en-us/library/ms172873.aspx Baca Data Objek dari File XML: https://msdn.microsoft. com / en-us / library / ms172872.aspx