Pergunta

Existe alguma classe no .NET framework que pode ler / gravar arquivos ini padrão:

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

Delphi tem o componente TIniFile e eu quero saber se há alguma coisa semelhante para C #?

Foi útil?

Solução

Os criadores do framework .NET quero que você use arquivos de configuração baseados em XML, em vez de arquivos INI. Então, não, não há nenhum built-in mecanismo para lê-los.

Existem soluções de terceiros disponíveis, no entanto.

Outras dicas

Prefácio

Em primeiro lugar, leia este post MSDN on as limitações de INI arquivos . Se ele se adapte às suas necessidades, a ler.

Esta é uma implementação concisa eu escrevi, utilizando o Windows original P / Invoke, por isso é suportado por todas as versões do Windows com o .NET instalado, (ou seja, Windows 98 - Windows 10). Venho por este meio colocá-la no domínio público -. Você é livre para usá-lo comercialmente sem atribuição

A pequena classe

Adicionar uma nova classe chamada IniFile.cs ao seu projeto:

using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;

// Change this to match your program's normal namespace
namespace MyProg
{
    class IniFile   // revision 11
    {
        string Path;
        string EXE = Assembly.GetExecutingAssembly().GetName().Name;

        [DllImport("kernel32", CharSet = CharSet.Unicode)]
        static extern long WritePrivateProfileString(string Section, string Key, string Value, string FilePath);

        [DllImport("kernel32", CharSet = CharSet.Unicode)]
        static extern int GetPrivateProfileString(string Section, string Key, string Default, StringBuilder RetVal, int Size, string FilePath);

        public IniFile(string IniPath = null)
        {
            Path = new FileInfo(IniPath ?? EXE + ".ini").FullName.ToString();
        }

        public string Read(string Key, string Section = null)
        {
            var RetVal = new StringBuilder(255);
            GetPrivateProfileString(Section ?? EXE, Key, "", RetVal, 255, Path);
            return RetVal.ToString();
        }

        public void Write(string Key, string Value, string Section = null)
        {
            WritePrivateProfileString(Section ?? EXE, Key, Value, Path);
        }

        public void DeleteKey(string Key, string Section = null)
        {
            Write(Key, null, Section ?? EXE);
        }

        public void DeleteSection(string Section = null)
        {
            Write(null, null, Section ?? EXE);
        }

        public bool KeyExists(string Key, string Section = null)
        {
            return Read(Key, Section).Length > 0;
        }
    }
}

Como usá-lo

Abra o arquivo INI em um dos 3 seguintes maneiras:

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

Você pode escrever alguns valores assim:

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

Para criar um arquivo como este:

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

Para ler os valores fora do arquivo INI:

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

Opcionalmente, você pode definir [Section] de:

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

Para criar um arquivo como este:

[Audio]
DefaultVolume=100

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

Você também pode verificar a existência de uma chave assim:

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

Você pode excluir uma chave assim:

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

Você também pode excluir uma seção inteira (incluindo todas as chaves) assim:

MyIni.DeleteSection("Web");

Por favor, sinta-se livre para comentar com qualquer melhorias!

Este artigo sobre CodeProject " Um arquivo INI classe manipulação usando C # " deveria ajuda.

O autor criou uma classe C # "Ini", que expõe duas funções de KERNEL32.dll. Estas funções são: WritePrivateProfileString e GetPrivateProfileString. Você vai precisar de dois namespaces:. System.Runtime.InteropServices e System.Text

Passos para usar a classe Ini

Em seu projeto de definição de namespace add

using INI;

Criar um inifile como este

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

Use IniWriteValue para escrever um novo valor para uma chave específica em uma seção ou o uso IniReadValue para ler um valor de uma chave em um ponto específico.

Nota: se você está começando do zero, você pode ler este artigo MSDN : Como: Adicionar aplicativo Arquivos de configuração para C # Projects . É a melhor maneira para configurar seu aplicativo.

Eu encontrei esta implementação simples:

http://bytes.com/topic/ / percepções líquida / 797169-lendo-analisar-ini-file-c

funciona bem para o que eu preciso.

Aqui está como você usá-lo:

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

Aqui está o código:

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

O código na resposta de joerage é inspirador.

Infelizmente, ele muda a caixa caráter das chaves e não manipula comentários. Então eu escrevi algo que deve ser suficiente robusta para ler (apenas) arquivos INI muito sujas e permite recuperar chaves como elas são.

Ele usa alguns LINQ, um caso aninhada insensível dicionário string para armazenar seções, chaves e valores, e ler o arquivo de uma vez.

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

Eu quero apresentar uma biblioteca IniParser Criei completamente em C #, por isso não contém dependências em qualquer sistema operacional, o que torna Mono compatível. Open Source com a licença MIT -então ele pode ser usado em qualquer código.

Você pode verificar a fonte no GitHub , e é also disponível como um pacote NuGet

É fortemente configurável , e realmente simples de usar .

Desculpe o plug descarado, mas espero que possa ser de ajuda de ninguém revisitar esta resposta.

Normalmente, quando você criar aplicativos usando C # eo framework .NET, você não vai usar arquivos INI. É mais comum para armazenar configurações em um arquivo de configuração baseada em XML ou no registro. No entanto, se as configurações do seu ações de software com um aplicativo herdado pode ser mais fácil de usar seu arquivo de configuração, em vez de duplicar a informação em outro lugar.

O framework .NET não suporta o uso de INI arquivos diretamente. No entanto, você pode usar funções de API do Windows com Platform Invocation Services (P / Invoke) para escrever e ler os arquivos. Neste link que criar uma classe que representa arquivos INI e usa as funções API do Windows para manipulá-los. Por favor, vá através do seguinte link.

Leitura e Escrita INI Arquivos

Estou atrasado para participar da festa, mas eu tive o mesmo problema hoje e eu escrevi a seguinte implementação:

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

Deve-se notar, que esta implementação não manipular seções ou propriedades que não são encontrados. Para conseguir isso, você deve estender o Dictionary<,> de classe para lidar com chaves não encontrados.


Para serializar uma instância de Dictionary<string, Dictionary<string, string>> a um arquivo .ini, eu uso o seguinte código:

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

Há uma Ini Analisador disponível em CommonLibrary.NET

Isto tem várias sobrecargas muito conveniente para se secções / valores e é muito leve.

Aqui está a minha própria versão, usando expressões regulares. Este código assume que o nome de cada secção é único - Se, no entanto isso não é verdade - faz sentido para substituir dicionário com List. Esta função suporta arquivo .ini comentando, a partir de ';' personagem. Seção inicia normalmente [seção], e pares de valores-chave também vem normalmente "chave = valor". Mesmo pressuposto que para seções -. Nome da chave é única

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

Tente este método:

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

Ele cria o dicionário onde a chave é "-". Você pode carregá-lo como este:

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

PeanutButter.INI é uma classe Nuget-embalados para INI arquivos manipulação. Ele suporta leitura / gravação, incluindo comentários - seus comentários são preservados na gravação. Parece ser razoavelmente popular, é testada e fácil de usar. Também é totalmente gratuita e de código aberto.

Disclaimer:. Eu sou o autor de PeanutButter.INI

Se você quer apenas um simples leitor, sem cortes e quaisquer outras DLLs aqui é solução simples:

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

Exemplo de uso:

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

Configuração de conteúdo do arquivo entretanto (como você vê suportes # símbolo de comentário de linha):

#command to run
command = php

#default script
action = index.php

#debug mode
#debug = true

#plain text mode
#plain = false

#icon = favico.ico

Se você só precisa de acesso de leitura e acesso não escrita e você estiver usando o Microsoft.Extensions.Confiuration (vem por padrão com ASP.NET Núcleo mas obras com programas regulares também) você pode usar o pacote NuGet Microsoft.Extensions.Configuration.Ini para importar arquivos ini para as definições de configuração.

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

Aqui está minha classe, funciona como um encanto:

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

    }

}

O uso é obviouse desde a sua uma classe estática, basta ligar IniFileManager.IniWriteValue para readsing uma seção ou IniFileManager.IniReadValue para a leitura de uma seção.

Você deve ler e gravar dados de arquivos XML desde que você pode salvar um objeto inteiro para xml e também você pode preencher um objeto a partir de um xml salvo. É melhor um fácil de manipular objetos.

Aqui está como fazê-lo: Write Data Object para um arquivo XML: https://msdn.microsoft.com/en -us / library / ms172873.aspx Leia objeto dados de um arquivo XML: https://msdn.microsoft.com/en -us / library / ms172872.aspx

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top