Membaca / menulis file INI

263

Apakah ada kelas dalam kerangka .NET yang dapat membaca / menulis file .ini standar:

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

Delphi memiliki TIniFilekomponen dan saya ingin tahu apakah ada yang serupa untuk C #?

zendar
sumber
RemObjects memiliki pustaka Delphi Prism yang disebut ShineOn yang mengirimkan kelas file INI yang serupa. Tetapi Anda perlu memiliki Delphi Prism untuk mengkompilasinya. code.remobjects.com/p/shineon
Lex Li
1
Mendapat masalah yang sama dan membuat perpustakaan saya sendiri untuk mem -parsing file ini: github.com/rickyah/ini-parser Semoga membantu
Ricardo Amores
5
Sama seperti Ricky, saya memutuskan untuk membuat solusi sendiri untuk ini. Ini tersedia di: github.com/MarioZ/MadMilkman.Ini
Mario Z

Jawaban:

185

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.

David Arno
sumber
24
Meskipun memang benar bahwa file konfigurasi XML adalah cara untuk pergi, ini masih bukan jawaban untuk pertanyaan, atau VLQ hanya untuk tautan.
Danny Beckett
6
@aloneguid Saya berpendapat bahwa sejumlah besar fitur yang tersedia sebenarnya berkontribusi pada file .NET config yang akhirnya menjadi raksasa raksasa dengan banyak keajaiban di dalamnya. Mereka telah menjadi "kode dalam file konfigurasi," dan ini mengarah pada banyak kompleksitas, perilaku aneh, dan membuat manajemen konfigurasi lebih sulit. (Saya melihat Anda, "penyedia" database, dan string koneksi.) Jadi, file INI juga umumnya lebih baik untuk pengeditan non-manual.
jpmc26
1
saya suka metode lama (P / Inovke) dan Anda dapat menggunakan unicode dengan metode lama seperti ini: File.WriteAllBytes (path, byte baru [] {0xFF, 0xFE});
sailfish009
2
Paket bagus tapi bisa lebih baik. Itu tidak dapat menguraikan nilai yang berisi '=' Atau '\ n' sepenuhnya
Ahmad Behjati
211

Kata pengantar

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.

Kelas kecil

Tambahkan kelas baru yang dipanggil IniFile.cske 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;
        }
    }
}

Bagaimana cara menggunakannya

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!

Danny Beckett
sumber
4
Saya sedikit terlambat, tapi ini GetSections()metode yang hilang .
stil
2
Mungkin default yang lebih tradisional adalah per-aplikasi (bukan per-assembly) file .ini seperti Path.GetFullPath(IniPath ?? Path.ChangeExtension(Application.ExecutablePath, ".ini")).
Eugene Ryabtsev
3
Benar benar hebat ! Taruh di github?
Emrys Myrooin
2
@danny Beckett, bagus sekali. Ini hampir persis sama dengan apa yang saya gunakan untuk um-tahun terakhir .Net. Diperbaharui dari kode lama tahun lalu.
Damian
10
Tua sekarang, dan sama seperti saya menghormati Raymond Chen, banyak keterbatasan dalam artikel itu adalah keterbatasan perpustakaan INI tertentu di Windows, dan bukan format INI itu sendiri. Yang lainnya, seperti izin granular, dapat dengan mudah dicegah melalui beberapa file. Seorang pejabat , dimodernisasi perpustakaan INI akan paling disambut, bahkan hari ini.
Joel Coehoorn
68

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: WritePrivateProfileStringdan GetPrivateProfileString. Anda akan membutuhkan dua ruang nama: System.Runtime.InteropServicesdan 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 IniWriteValueuntuk menulis nilai baru ke kunci tertentu di bagian atau gunakan IniReadValueuntuk 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.

percikan
sumber
1
Saya ingin membaca file INI lengkap. Bagaimana melakukan hal yang sama alih-alih membaca bagian, kunci
venkat
ini berhasil untuk saya, dan kemudian berhenti bekerja dari titik lain. Tidak tahu lagi apa yang berbeda di bawah tenda
nawfal
1
Watch out menggunakan fungsi Win32 API yang sudah usang ini. Info lebih lanjut: stackoverflow.com/questions/11451641/...
Pedro77
Saya menggunakan pendekatan ini untuk sementara, tetapi peningkatan keamanan mulai di Win7 telah cukup banyak membunuh ini untuk saya. Anda masih dapat menggunakan pendekatan ini, tetapi Anda harus menyimpan .ini di ProgramData dan membuat aplikasi Anda baca / tulis di sana.
Jess
Jangan menyimpan konfigurasi aplikasi file ini di ProgramData. Mereka tidak termasuk dalam Registry atau ProgramData. File konfigurasi seharusnya ada di folder LocalApplicationData.
Deegee
47

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);
    }
}
joerage
sumber
38
+1 untuk mengimbangi downvote di atas. Apa yang sebenarnya Anda keluhkan? Dia bilang dia menemukannya. Apakah Anda menurunkannya karena tidak menemukan satu dengan pengakses generik dan penggunaan pembuat string?
Tormod
1
@Tormod: Seandainya aku bisa menurunkan komentar. Ini adalah forum teknis ketika kita memilih solusi, bukan niat (jelas positif). Jika solusi yang diposting oleh Knuth sendiri memiliki kekurangan, itu akan - dan harus - ditunjukkan. Tidak masalah jika solusinya ditemukan atau ditulis oleh poster.
ya23
7
Saya pikir Anda meregangkan definisi "cacat". Jika solusinya tidak menekankan kepekaan Anda, maka jangan undur diri. Saya baru saja meninggalkan pesan yang mengatakan bahwa saya sudah meniadakan downvote-nya sehingga 7 orang lain yang membenarkan komentar saya tidak akan melakukan ini sendiri.
Tormod
21

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();
    }
}
Larry
sumber
4
dan terima kasih karena tidak memasukkannya catch (Exception ex) { throw ex; }ke sana
Mark Schultheiss
1
Baik! Setidaknya beberapa perubahan diperlukan untuk bekerja lebih baik. Baris 16: ini [""] = currentSection; Kepada: // ini [""] = currentSection; Ini harus dihapus karena setiap kali elemen pertama [0] akan menjadi segmen kosong karena inisialisasi ini. Baris 36: currentSection [line.Substring (0, idx)] = line.Substring (idx + 1); Kepada: currentSection [line.Substring (0, idx) .Trim ()] = line.Substring (idx + 1) .Trim (); Kunci dan nilai harus dipangkas secara independen, tidak hanya pada garis Trim. Dalam INI seperti file konfigurasi biasanya yang menambahkan pasangan K-> V cenderung untuk menyelaraskan ini di dalam bagian. Terima kasih!
LXSoft
Sudah lama à. Terima kasih banyak atas saran Anda. Mereka semua masuk akal dan pantas kode ini untuk memiliki penyegaran yang baik.
Larry
13

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.

Ricardo Amores
sumber
4

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.Iniuntuk 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();
}
Scott Chamberlain
sumber
Hanya untuk menambahkan bahwa Anda kemudian mendapatkan kunci denganConfiguration["keyname"]
kofifus
@scott masalah yang saya alami adalah untuk alasan apa pun IIS tidak mengenalinya ketika aplikasi sedang berjalan. itu digunakan, dan di sana, tetapi tidak dikonsumsi. HTTP 500.30 dikembalikan dan log Aplikasi IIS mengatakan "file konfigurasi tidak ditemukan dan bukan opsional."
one.beat.consumer
3

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.

Membaca dan Menulis File INI

Tidak dikenal
sumber
4
Jauhi Registry! Data konfigurasi aplikasi tidak boleh disimpan dalam Registry.
Deegee
3

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
BIOHAZARD
sumber
3

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));
Petr Vobornik
sumber
3

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.

daf
sumber
Bisakah Anda memberikan tautan ke dokumentasi PeanutButter.INI?
Shroombaker
3

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());
tidak diketahui6656
sumber
2

Ada Parser Ini tersedia di CommonLibrary.NET

Ini memiliki berbagai kelebihan yang sangat mudah untuk mendapatkan bagian / nilai dan sangat ringan.

james
sumber
1
Jika tidak jelas dari melihat tingkat atas perpustakaan (itu tidak jelas bagi saya!), Kelas IniDcoument et al berada di ComLib.IO.
Tim Keating
2
Bagi siapa pun yang melihat rute ini, CommonLibrary.NET tampaknya tidak mengikuti konvensi .INI. Ini menggunakan tanda titik dua ":" sebagai pembatas alih-alih tanda sama dengan, dan tidak menangani komentar (memulai garis dengan tanda titik koma atau pound akan menyebabkan penguraian gagal).
jmmr
2

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;
}
TarmoPikaro
sumber
Fungsi itu tidak berfungsi, bagi saya: Ini lupa satu bagian dalam dua. Saya mencoba dengan dan tanpa garis kosong sebelum [Bagian].
iksess
dapatkah Anda menyalin contoh .ini yang tidak berfungsi?
TarmoPikaro
-3

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.

Erwin Draconis
sumber
Pendekatan ini telah ditunjukkan dan dijelaskan dalam jawaban lain . Apa yang ditambahkan jawaban Anda yang tidak dicakup oleh jawaban itu?
Palec
Berhati-hatilah karena hanya berfungsi jika file .ini disimpan dalam UNICODE (16bit LE). Gunakan Notepad ++ untuk mengonversi teks menjadi unicode, karena jika Anda menyimpannya di UTF-8 tidak akan berfungsi. ANSI juga dapat diterima, tetapi Anda tidak dapat membaca huruf beraksen
user2991288
-6

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

Daniel
sumber
1
Tautan ke sumber daya eksternal dianjurkan, tetapi tolong tambahkan konteks di sekitar tautan sehingga sesama pengguna Anda akan mengetahui apa itu dan mengapa ada di sana. Selalu kutip bagian yang paling relevan dari tautan penting, jika situs target tidak dapat dijangkau atau offline secara permanen.
davejal
Saya percaya bahwa judul tautan sangat jelas tentang referensi / konteksnya. Jika Anda pikir itu tidak cukup, silakan mengeditnya.
Daniel
1
Tidak menjawab pertanyaan aktual.
Erik Knowles