INI dosyası okuma / yazma


263

.NET çerçevesinde standart .ini dosyalarını okuyabilen / yazabilen herhangi bir sınıf var mı:

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

Delphi TIniFilebileşeni vardır ve C # için benzer bir şey olup olmadığını bilmek istiyorum?


RemObjects, benzer bir INI dosya sınıfını gönderen ShineOn adlı bir Delphi Prism kütüphanesine sahiptir. Ancak henüz derlenmiş bir derleme olmadığı için .NET'ten kaynak için derlemek için Delphi Prism'e ihtiyacınız var. code.remobjects.com/p/shineon
Lex Li

1
Aynı sorunu aldım ve ini dosyalarını ayrıştırmak için kendi kütüphanemi yaptım: github.com/rickyah/ini-parser Umarım yardımcı olur
Ricardo Amores

5
Tıpkı Ricky gibi buna kendi çözümümü yapmaya karar verdim. Sunulduğu
Mario Z

Yanıtlar:


185

.NET çerçevesinin yaratıcıları, INI dosyaları yerine XML tabanlı yapılandırma dosyaları kullanmanızı ister. Yani hayır, onları okumak için yerleşik bir mekanizma yok.

Yine de üçüncü taraf çözümleri var.


24
XML yapılandırma dosyalarının gidilecek yol olduğu doğru olsa da, bu hala sorunun cevabı değildir veya yalnızca bağlantı için VLQ'dur.
Danny Beckett

6
@aloneguid Ben mevcut özelliklerin büyük bir dizi aslında onları bir sürü büyü ile garip behemoths sonuçlanan .NET yapılandırma dosyaları katkıda bulundu. "Yapılandırma dosyasında kod" haline geldiler ve bu çok fazla karmaşıklığa, tuhaf davranışlara yol açıyor ve yapılandırma yönetimini zorlaştırıyor. (Sana, veritabanı "sağlayıcıları" ve bağlantı dizeleri bakıyorum.) Yani INI dosyaları da manuel olmayan düzenleme için de genellikle daha iyidir.
jpmc26

1
eski yöntemi (P / Inovke) seviyorum ve böyle eski yöntemle unicode kullanabilirsiniz: File.WriteAllBytes (yol, yeni bayt [] {0xFF, 0xFE});
sailfish009

2
İyi bir paket ama daha iyi olabilir. Tamamen '=' Veya '\ n' içeren bir değer ayrıştırılamaz
Ahmad Behjati

211

önsöz

İlk olarak, INI dosyalarının sınırlamaları hakkındaki bu MSDN blog gönderisini okuyun . İhtiyaçlarınıza uygunsa okumaya devam edin.

Bu, orijinal Windows P / Invoke kullanarak yazdığım kısa bir uygulamadır, bu nedenle .NET yüklü tüm Windows sürümleri tarafından desteklenir (yani Windows 98 - Windows 10). Bu vesileyle kamu malı olarak yayınlıyorum - ticari olarak atıfta bulunmadan kullanabilirsiniz.

Küçük sınıf

IniFile.csProjenize yeni bir sınıf ekleyin:

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

Bu nasıl kullanılır

INI dosyasını aşağıdaki 3 yoldan biriyle açın:

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

Bunun gibi bazı değerler yazabilirsiniz:

MyIni.Write("DefaultVolume", "100");
MyIni.Write("HomePage", "http://www.google.com");

Bunun gibi bir dosya oluşturmak için:

[MyProg]
DefaultVolume=100
HomePage=http://www.google.com

INI dosyasındaki değerleri okumak için:

var DefaultVolume = IniFile.Read("DefaultVolume");
var HomePage = IniFile.Read("HomePage");

İsteğe bağlı olarak şunları ayarlayabilirsiniz [Section]:

MyIni.Write("DefaultVolume", "100", "Audio");
MyIni.Write("HomePage", "http://www.google.com", "Web");

Bunun gibi bir dosya oluşturmak için:

[Audio]
DefaultVolume=100

[Web]
HomePage=http://www.google.com

Bunun gibi bir anahtarın varlığını da kontrol edebilirsiniz:

if(!MyIni.KeyExists("DefaultVolume", "Audio"))
{
    MyIni.Write("DefaultVolume", "100", "Audio");
}

Bunun gibi bir anahtarı silebilirsiniz:

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

Ayrıca tüm bölümü (tüm anahtarlar dahil) şu şekilde silebilirsiniz:

MyIni.DeleteSection("Web");

Lütfen herhangi bir iyileştirme ile yorum yapmaktan çekinmeyin!


4
Biraz geç kaldım ama GetSections()yöntemi eksik .
stil

2
Belki daha geleneksel bir varsayılan uygulama başına (montaj başına değil) .ini dosyaları gibi olacaktır Path.GetFullPath(IniPath ?? Path.ChangeExtension(Application.ExecutablePath, ".ini")).
Eugene Ryabtsev

3
Gerçekten harika ! Github üzerine koy?
Emrys Myrooin

2
@ danny Beckett, güzel yapılmış. Bu neredeyse .Net geçmiş um-yıllarında kullandığımla tamamen aynı. Yıllar önce eski koddan yükseltildi.
Damian

10
Eskiden ve Raymond Chen'e saygı duyduğum kadarıyla, bu makaledeki sınırlamaların çoğu, INI formatının kendisi değil, Windows'daki belirli INI kütüphanesinin sınırlamalarıydı. Ayrıntılı izinler gibi diğerleri, birden fazla dosya aracılığıyla kolayca kaldırılabilir. Bir resmi , modernize INI kütüphane bugün bile, en-memnuniyetle karşılanacaktır.
Joel Coehoorn

68

CodeProject Bu makalede " C # kullanarak bir INI dosya işleme sınıfı " yardımcı olacaktır.

Yazar, KERNEL32.dll'den iki işlevi ortaya çıkaran bir C # sınıfı "Ini" oluşturdu. Bu işlevler: WritePrivateProfileStringve GetPrivateProfileString. İki ad alanına ihtiyacınız olacak: System.Runtime.InteropServicesve System.Text.

Ini sınıfını kullanma adımları

Proje ad alanı tanımınıza şunu ekleyin:

using INI;

Bunun gibi bir INIFile oluşturun

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

IniWriteValueBir bölümdeki belirli bir tuşa yeni bir değer yazmak için kullanın veya belirli IniReadValuebir Bölümdeki bir anahtardan FROM değerini okumak için kullanın .

Not: Sıfırdan başlıyorsanız, şu MSDN makalesini okuyabilirsiniz : Nasıl yapılır: C # Projelerine Uygulama Yapılandırma Dosyaları Ekleme . Uygulamanızı yapılandırmanın daha iyi bir yolu.


1
Tam INI dosyasını okumak istiyorum. Aynı şeyi okuma bölümü yerine yapmak için, anahtar
venkat

bu benim için çalıştı ve sonra başka bir noktadan çalışmayı bıraktı. Başlık altında neyin farklı gittiğini bilmiyorum
nawfal

1
Kullanımdan kaldırılmış bu Win32 API işlevlerini kullanarak dikkat edin. Daha fazla bilgi: stackoverflow.com/questions/11451641/…
Pedro77

Bu yaklaşımı bir süre kullandım, ancak Win7'de başlayan güvenlik geliştirmeleri bunu benim için neredeyse öldürdü. Bu yaklaşımı kullanmaya devam edebilirsiniz, ancak .ini dosyasını ProgramData'da depolayacak ve uygulamanızın orada okumasını / yazmasını sağlayabilirsiniz.
Jess

Uygulama yapılandırması ini dosyalarını ProgramData'ya kaydetmeyin. Onlar Kayıt Defteri veya ProgramData ait değildir. Yapılandırma dosyalarının LocalApplicationData klasörlerinde olması gerekir.
deegee

47

Bu basit uygulamayı buldum:

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

İhtiyacım olan şey için iyi çalışıyor.

İşte nasıl kullanacağınız:

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

İşte kod:

using System;
using System.IO;
using System.Collections;

public class IniParser
{
    private Hashtable keyPairs = new Hashtable();
    private String iniFilePath;

    private struct SectionPair
    {
        public String Section;
        public String Key;
    }

    /// <summary>
    /// Opens the INI file at the given path and enumerates the values in the IniParser.
    /// </summary>
    /// <param name="iniPath">Full path to INI file.</param>
    public IniParser(String iniPath)
    {
        TextReader iniFile = null;
        String strLine = null;
        String currentRoot = null;
        String[] keyPair = null;

        iniFilePath = iniPath;

        if (File.Exists(iniPath))
        {
            try
            {
                iniFile = new StreamReader(iniPath);

                strLine = iniFile.ReadLine();

                while (strLine != null)
                {
                    strLine = strLine.Trim().ToUpper();

                    if (strLine != "")
                    {
                        if (strLine.StartsWith("[") && strLine.EndsWith("]"))
                        {
                            currentRoot = strLine.Substring(1, strLine.Length - 2);
                        }
                        else
                        {
                            keyPair = strLine.Split(new char[] { '=' }, 2);

                            SectionPair sectionPair;
                            String value = null;

                            if (currentRoot == null)
                                currentRoot = "ROOT";

                            sectionPair.Section = currentRoot;
                            sectionPair.Key = keyPair[0];

                            if (keyPair.Length > 1)
                                value = keyPair[1];

                            keyPairs.Add(sectionPair, value);
                        }
                    }

                    strLine = iniFile.ReadLine();
                }

            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (iniFile != null)
                    iniFile.Close();
            }
        }
        else
            throw new FileNotFoundException("Unable to locate " + iniPath);

    }

    /// <summary>
    /// Returns the value for the given section, key pair.
    /// </summary>
    /// <param name="sectionName">Section name.</param>
    /// <param name="settingName">Key name.</param>
    public String GetSetting(String sectionName, String settingName)
    {
        SectionPair sectionPair;
        sectionPair.Section = sectionName.ToUpper();
        sectionPair.Key = settingName.ToUpper();

        return (String)keyPairs[sectionPair];
    }

    /// <summary>
    /// Enumerates all lines for given section.
    /// </summary>
    /// <param name="sectionName">Section to enum.</param>
    public String[] EnumSection(String sectionName)
    {
        ArrayList tmpArray = new ArrayList();

        foreach (SectionPair pair in keyPairs.Keys)
        {
            if (pair.Section == sectionName.ToUpper())
                tmpArray.Add(pair.Key);
        }

        return (String[])tmpArray.ToArray(typeof(String));
    }

    /// <summary>
    /// Adds or replaces a setting to the table to be saved.
    /// </summary>
    /// <param name="sectionName">Section to add under.</param>
    /// <param name="settingName">Key name to add.</param>
    /// <param name="settingValue">Value of key.</param>
    public void AddSetting(String sectionName, String settingName, String settingValue)
    {
        SectionPair sectionPair;
        sectionPair.Section = sectionName.ToUpper();
        sectionPair.Key = settingName.ToUpper();

        if (keyPairs.ContainsKey(sectionPair))
            keyPairs.Remove(sectionPair);

        keyPairs.Add(sectionPair, settingValue);
    }

    /// <summary>
    /// Adds or replaces a setting to the table to be saved with a null value.
    /// </summary>
    /// <param name="sectionName">Section to add under.</param>
    /// <param name="settingName">Key name to add.</param>
    public void AddSetting(String sectionName, String settingName)
    {
        AddSetting(sectionName, settingName, null);
    }

    /// <summary>
    /// Remove a setting.
    /// </summary>
    /// <param name="sectionName">Section to add under.</param>
    /// <param name="settingName">Key name to add.</param>
    public void DeleteSetting(String sectionName, String settingName)
    {
        SectionPair sectionPair;
        sectionPair.Section = sectionName.ToUpper();
        sectionPair.Key = settingName.ToUpper();

        if (keyPairs.ContainsKey(sectionPair))
            keyPairs.Remove(sectionPair);
    }

    /// <summary>
    /// Save settings to new file.
    /// </summary>
    /// <param name="newFilePath">New file path.</param>
    public void SaveSettings(String newFilePath)
    {
        ArrayList sections = new ArrayList();
        String tmpValue = "";
        String strToSave = "";

        foreach (SectionPair sectionPair in keyPairs.Keys)
        {
            if (!sections.Contains(sectionPair.Section))
                sections.Add(sectionPair.Section);
        }

        foreach (String section in sections)
        {
            strToSave += ("[" + section + "]\r\n");

            foreach (SectionPair sectionPair in keyPairs.Keys)
            {
                if (sectionPair.Section == section)
                {
                    tmpValue = (String)keyPairs[sectionPair];

                    if (tmpValue != null)
                        tmpValue = "=" + tmpValue;

                    strToSave += (sectionPair.Key + tmpValue + "\r\n");
                }
            }

            strToSave += "\r\n";
        }

        try
        {
            TextWriter tw = new StreamWriter(newFilePath);
            tw.Write(strToSave);
            tw.Close();
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

    /// <summary>
    /// Save settings back to ini file.
    /// </summary>
    public void SaveSettings()
    {
        SaveSettings(iniFilePath);
    }
}

38
+1. Gerçekten ne hakkında şikayet ediyorsun? BULDUĞUNU söyledi. Genel erişimcileri ve stringbuilder kullanımı olan birini bulamadığı için onu küçümsüyor musunuz?
Tormod

1
@Tormod: Yorumunu aşağıya indirebilsem. Çözümlere oy verdiğimizde (açık bir şekilde olumlu) niyet değil teknik bir forum. Knuth tarafından yayınlanan bir çözümün kusurları olsaydı, belirtilecekti ve yapılmalıdır. Çözümün poster tarafından bulunması veya yazılması önemli değildir.
ya23

7
"Kusur" un tanımını uzattığını düşünüyorum. Çözüm hassasiyetlerinizi vurgulamıyorsa, o zaman basitçe yükselmeyin. Yorumumu iptal eden diğer 7 adamın bunu kendileri yapmamaları için aşağı notunu zaten reddettiğimi söyleyen bir not bıraktım.
Tormod

21

Joerage'ın cevabındaki kod ilham vericidir.

Ne yazık ki, tuşların karakter kasasını değiştirir ve yorumları işlemez. Bu yüzden (sadece) çok kirli INI dosyalarını okumak için yeterince sağlam olması gereken bir şey yazdım ve anahtarları oldukları gibi almayı sağlar.

Bazı LINQ, bölümleri, anahtarları ve değerleri saklamak ve dosyayı tek seferde okumak için iç içe geçmiş büyük / küçük harf duyarsız bir dize sözlüğü kullanır.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

class IniReader
{
    Dictionary<string, Dictionary<string, string>> ini = new Dictionary<string, Dictionary<string, string>>(StringComparer.InvariantCultureIgnoreCase);

    public IniReader(string file)
    {
        var txt = File.ReadAllText(file);

        Dictionary<string, string> currentSection = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);

        ini[""] = currentSection;

        foreach(var line in txt.Split(new[]{"\n"}, StringSplitOptions.RemoveEmptyEntries)
                               .Where(t => !string.IsNullOrWhiteSpace(t))
                               .Select(t => t.Trim()))
        {
            if (line.StartsWith(";"))
                continue;

            if (line.StartsWith("[") && line.EndsWith("]"))
            {
                currentSection = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
                ini[line.Substring(1, line.LastIndexOf("]") - 1)] = currentSection;
                continue;
            }

            var idx = line.IndexOf("=");
            if (idx == -1)
                currentSection[line] = "";
            else
                currentSection[line.Substring(0, idx)] = line.Substring(idx + 1);
        }
    }

    public string GetValue(string key)
    {
        return GetValue(key, "", "");
    }

    public string GetValue(string key, string section)
    {
        return GetValue(key, section, "");
    }

    public string GetValue(string key, string section, string @default)
    {
        if (!ini.ContainsKey(section))
            return @default;

        if (!ini[section].ContainsKey(key))
            return @default;

        return ini[section][key];
    }

    public string[] GetKeys(string section)
    {
        if (!ini.ContainsKey(section))
            return new string[0];

        return ini[section].Keys.ToArray();
    }

    public string[] GetSections()
    {
        return ini.Keys.Where(t => t != "").ToArray();
    }
}

4
ve bunu catch (Exception ex) { throw ex; }oraya
koymadığınız

1
İyi! En azından daha iyi çalışabilmek için bazı değişikliklerin yapılması gerekiyor. Satır 16: ini [""] = currentSection; Alıcı: // ini [""] = currentSection; Bu başlatma nedeniyle ilk eleman [0] boş bir segment olacağından bu kaldırılmalıdır. Satır 36: currentSection [line.Substring (0, idx)] = line.Substring (idx + 1); Alıcı: currentSection [line.Substring (0, idx) .Trim ()] = line.Substring (idx + 1) .Trim (); Anahtar ve değerler, yalnızca Trim hattında değil, bağımsız olarak kesilmelidir. INI benzeri yapılandırma dosyalarında genellikle K-> V çiftleri ekleyen dosyalar bu eşitlikleri bölümler içinde hizalama eğilimindedir. Teşekkür ederim!
LXSoft

Wew uzun zaman oldu. Önerileriniz için çok teşekkürler. Hepsi mantıklı ve iyi bir yenileme için bu kodu hak ediyor.
Larry

13

Tamamen c # 'de oluşturduğum bir IniParser kütüphanesini tanıtmak istiyorum, bu yüzden Mono uyumlu hale getiren herhangi bir işletim sisteminde bağımlılık içermiyor. MIT lisansı ile Açık Kaynak - böylece herhangi bir kodda kullanılabilir.

GitHub'da kaynağı kontrol edebilirsiniz ve ayrıca NuGet paketi olarak da mevcuttur

Çok yapılandırılabilir ve kullanımı gerçekten basit .

Utanmaz fiş için üzgünüm ama umarım bu cevabı tekrar ziyaret eden herkesin yardımcı olabilir.


4

Yalnızca okuma erişimine ihtiyacınız varsa ve yazma erişimine ihtiyacınız yoksa ve Microsoft.Extensions.Confiuration(varsayılan olarak ASP.NET Core ile birlikte gelir, ancak normal programlarla da çalışır) kullanıyorsanız, Microsoft.Extensions.Configuration.Iniini dosyalarını yapılandırma ayarlarınıza aktarmak için NuGet paketini kullanabilirsiniz .

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

Sadece eklemek için anahtarları almakConfiguration["keyname"]
kofifus

@scott sorunum nedense uygulama çalışırken IIS tanımıyor nedense. konuşlandırılır ve orada kullanılır, ancak tüketilmez. HTTP 500.30 döndü ve IIS Uygulama günlüğü "yapılandırma dosyası bulunamadı ve isteğe bağlı değil" diyor.
one.beat.consumer

3

Genellikle, C # ve .NET çerçevesini kullanarak uygulamalar oluşturduğunuzda, INI dosyalarını kullanmazsınız. Ayarları XML tabanlı bir yapılandırma dosyasında veya kayıt defterinde saklamak daha yaygındır. Ancak, yazılımınız ayarları eski bir uygulamayla paylaşıyorsa, bilgileri başka bir yerde çoğaltmak yerine yapılandırma dosyasını kullanmak daha kolay olabilir.

.NET çerçevesi, INI dosyalarının doğrudan kullanımını desteklemez. Bununla birlikte, dosyalara yazmak ve dosyalardan okumak için Platform Invocation Services (P / Invoke) ile Windows API işlevlerini kullanabilirsiniz. Bu bağlantıda, INI dosyalarını temsil eden ve onları işlemek için Windows API işlevlerini kullanan bir sınıf oluşturuyoruz. Lütfen aşağıdaki bağlantıdan geçin.

INI Dosyalarını Okuma ve Yazma


4
Kayıt Defterinden uzak durun! Uygulama yapılandırma verileri Kayıt Defterine kaydedilmemelidir.
Deegee

3

Bölümler ve diğer dll'ler olmadan sadece basit bir okuyucu istiyorsanız basit bir çözümdür:

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

Kullanım örneği:

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

Bu arada dosya içeriğini yapılandır (gördüğünüz gibi satır yorumu için # sembolünü destekler):

#command to run
command = php

#default script
action = index.php

#debug mode
#debug = true

#plain text mode
#plain = false

#icon = favico.ico

3

Bu yöntemi deneyin:

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

Anahtarın "-" olduğu sözlüğü oluşturur. Bunu şu şekilde yükleyebilirsiniz:

var dict = ParseIniDataWithSections(File.ReadAllLines(fileName));

3

PeanutButter.INI , INI dosyalarının işlenmesi için Nuget ile paketlenmiş bir sınıftır. Yorumlar dahil olmak üzere okuma / yazma destekler - yorumlarınız yazma sırasında korunur. Oldukça popüler gibi görünüyor, test edildi ve kullanımı kolay. Aynı zamanda tamamen ücretsiz ve açık kaynaklıdır.

Feragatname: Ben PeanutButter.INI'nin yazarıyım.


Lütfen PeanutButter.INI belgelerine bir bağlantı verebilir misiniz?
Shroombaker


3

Partiye katılmak için geç kaldım, ancak bugün de aynı sorunu yaşadım ve aşağıdaki uygulamayı yazdım:

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"];
}

Bu uygulamanın, bulunmayan bölümleri veya özellikleri işlemediğine dikkat edilmelidir. Bunu başarmak için, Dictionary<,>-class öğesini asılsız anahtarları işleyecek şekilde genişletmelisiniz .


Bir örneğini seri hale getirmek Dictionary<string, Dictionary<string, string>>bir karşı .ini-Dosya, ben şu kodu kullanın:

string targetpath = .........;
Dictionary<string, Dictionary<string, string>> ini = ........;
StringBuilder sb = new StringBuilder();

foreach (string section in ini.Keys)
{
    sb.AppendLine($"[{section}]");

    foreach (string property in ini[section].Keys)
        sb.AppendLine($"{property}={ini[section][property]");
}

File.WriteAllText(targetpath, sb.ToString());

2

CommonLibrary.NET içinde bir Ini Ayrıştırıcı var

Bu, bölüm / değer almak için çeşitli çok aşırı yüklemelere sahiptir ve çok hafiftir.


1
Kütüphanenin en üst seviyesine bakmanın belli olmadığı durumlarda (benim için açık değildi!), IniDcoument sınıfı ve arkadaşları ComLib.IO'dadır.
Tim Keating

2
Bu yola bakan herkes için CommonLibrary.NET .INI kurallarına uymuyor gibi görünüyor. Eşittir işareti yerine ayırıcı olarak iki nokta üst üste ":" kullanır ve yorumları işlemez (noktalı virgül veya kare işareti olan bir satırın başlatılması ayrıştırma işleminin başarısız olmasına neden olur).
jmmr

2

İşte düzenli ifadeler kullanarak kendi sürümüm. Bu kod, her bölüm adının benzersiz olduğunu varsayar - ancak bu doğru değilse - Sözlüğü Listeyle değiştirmek mantıklıdır. Bu işlev, ';' ile başlayan .ini dosyası yorumlamasını destekler karakter. Bölüm normal olarak başlar [bölüm] ve anahtar / değer çiftleri de normal olarak "anahtar = değer" olarak gelir. Bölümlerle aynı varsayım - anahtar adı benzersizdir.

/// <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;
}

Bu işlev benim için işe yaramıyor: İkide bir bölümü unutuyor. [Bölüm] 'den önce boş satırlarla ve boş satırlarla denedim.
iksess

çalışmayan .ini örneğinizi kopyalayabilir misiniz?
TarmoPikaro

-3

İşte benim sınıfım, bir cazibe gibi çalışır:

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

    }

}

Statik bir sınıf olduğundan kullanımı obviouse, sadece bir bölümü okumak için IniFileManager.IniWriteValue veya bir bölümü okumak için IniFileManager.IniReadValue arayın.


Bu yaklaşım daha önce başka bir cevapta gösterilmiş ve açıklanmıştır . Cevabınız bunun kapsamına girmeyen ne ekliyor?
Palec

Yalnızca .ini dosyası UNICODE (16bit LE) içine kaydedilmişse çalışır. UTF-8'de çalışmayacaksanız metni unicode'a dönüştürmek için Notepad ++ kullanın. Ayrıca ANSI kabul edilebilir, ancak aksanlı harfleri okuyamazsınız
user2991288

-6

Tüm bir nesneyi xml'ye kaydedebileceğiniz ve ayrıca kaydedilmiş bir xml'den bir nesneyi doldurabileceğiniz için xml dosyalarından veri okumalı ve yazmalısınız. Nesneleri manipüle etmek daha kolaydır.

Bunu şu şekilde yapabilirsiniz: Nesne Verilerini XML Dosyasına Yazma: https://msdn.microsoft.com/en-us/library/ms172873.aspx Bir XML Dosyasından Nesne Verilerini Okuma: https://msdn.microsoft. com / tr-tr / kütüphane / ms172872.aspx


1
Dış kaynaklara bağlantılar teşvik edilir, ancak lütfen kullanıcılarınızın ne olduğunu ve neden orada olduğunu bilmeleri için bağlantının çevresine bağlam ekleyin. Hedef siteye erişilemiyorsa veya kalıcı olarak çevrimdışı olursa, her zaman önemli bir bağlantının en alakalı kısmını belirtin.
davejal

Bağlantı başlıklarının referansları / bağlamları hakkında çok net olduğuna inanıyorum. Bunun yeterli olmadığını düşünüyorsanız, düzenlemekten çekinmeyin.
Daniel

1
Asıl soruya değinmiyor.
Erik Knowles
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.