O .Net Carregar e analisar um arquivo de propriedades equivalente à classe Java Properties?

StackOverflow https://stackoverflow.com/questions/485659

Pergunta

Existe uma maneira fácil em C# para ler um arquivo de propriedades que possui cada propriedade em uma linha separada seguida por um sinal igual e o valor, como o seguinte:

ServerName=prod-srv1
Port=8888
CustomProperty=Any value

Em Java, a classe Properties lida com isso analisando facilmente:

Properties myProperties=new Properties();
FileInputStream fis = new FileInputStream (new File("CustomProps.properties"));
myProperties.load(fis);
System.out.println(myProperties.getProperty("ServerName"));
System.out.println(myProperties.getProperty("CustomProperty"));

Eu posso carregar facilmente o arquivo em C# e analisar cada linha, mas há uma maneira integrada de obter uma propriedade facilmente sem precisar analisar o nome da chave e igual a me assinar? As informações C# que encontrei parecem sempre favorecer o XML, mas este é um arquivo existente que eu não controlo e prefiro mantê -lo no formato existente, pois exigirá mais tempo para que outra equipe mude para XML do que analisar o arquivo existente.

Foi útil?

Solução

Não, não há suporte interno para isso.

Você tem que fazer o seu próprio "inifileReader". Talvez algo assim?

var data = new Dictionary<string, string>();
foreach (var row in File.ReadAllLines(PATH_TO_FILE))
  data.Add(row.Split('=')[0], string.Join("=",row.Split('=').Skip(1).ToArray()));

Console.WriteLine(data["ServerName"]);

Editar: Atualizado para refletir o comentário de Paul.

Outras dicas

A maioria dos arquivos Java ".Properties" pode ser dividida assumindo que o "=" é o separador - mas o formato é significativamente mais complicado do que isso e permite incorporar espaços, iguais, novas linhas e quaisquer caracteres unicode em nome ou valor da propriedade.

Eu precisava carregar algumas propriedades Java para um aplicativo C#, então implementei Javaproperties.cs para ler e escrever corretamente arquivos formatados ".Properties" usando a mesma abordagem que a versão Java - você pode encontrá -lo em http://www.kajabity.com/index.php/2009/06/loading-java-properties-files-in-csharp/.

Lá, você encontrará um arquivo zip contendo a fonte C# para a classe e alguns arquivos de propriedades de amostra com quem o testei.

Apreciar!

Classe final. Obrigado @Exxl.

public class Properties
{
    private Dictionary<String, String> list;
    private String filename;

    public Properties(String file)
    {
        reload(file);
    }

    public String get(String field, String defValue)
    {
        return (get(field) == null) ? (defValue) : (get(field));
    }
    public String get(String field)
    {
        return (list.ContainsKey(field))?(list[field]):(null);
    }

    public void set(String field, Object value)
    {
        if (!list.ContainsKey(field))
            list.Add(field, value.ToString());
        else
            list[field] = value.ToString();
    }

    public void Save()
    {
        Save(this.filename);
    }

    public void Save(String filename)
    {
        this.filename = filename;

        if (!System.IO.File.Exists(filename))
            System.IO.File.Create(filename);

        System.IO.StreamWriter file = new System.IO.StreamWriter(filename);

        foreach(String prop in list.Keys.ToArray())
            if (!String.IsNullOrWhiteSpace(list[prop]))
                file.WriteLine(prop + "=" + list[prop]);

        file.Close();
    }

    public void reload()
    {
        reload(this.filename);
    }

    public void reload(String filename)
    {
        this.filename = filename;
        list = new Dictionary<String, String>();

        if (System.IO.File.Exists(filename))
            loadFromFile(filename);
        else
            System.IO.File.Create(filename);
    }

    private void loadFromFile(String file)
    {
        foreach (String line in System.IO.File.ReadAllLines(file))
        {
            if ((!String.IsNullOrEmpty(line)) &&
                (!line.StartsWith(";")) &&
                (!line.StartsWith("#")) &&
                (!line.StartsWith("'")) &&
                (line.Contains('=')))
            {
                int index = line.IndexOf('=');
                String key = line.Substring(0, index).Trim();
                String value = line.Substring(index + 1).Trim();

                if ((value.StartsWith("\"") && value.EndsWith("\"")) ||
                    (value.StartsWith("'") && value.EndsWith("'")))
                {
                    value = value.Substring(1, value.Length - 2);
                }

                try
                {
                    //ignore dublicates
                    list.Add(key, value);
                }
                catch { }
            }
        }
    }


}

Uso de amostra:

//load
Properties config = new Properties(fileConfig);
//get value whith default value
com_port.Text = config.get("com_port", "1");
//set value
config.set("com_port", com_port.Text);
//save
config.Save()

Eu escrevi um método que permite linhas da EMTY, resultado e citação dentro do arquivo.

Exemplos:

var1 = "value1"
var2 = 'valor2'

'var3 = exceto
; var4 = exceto também

Aqui está o método:

public static IDictionary ReadDictionaryFile(string fileName)
{
    Dictionary<string, string> dictionary = new Dictionary<string, string>();
    foreach (string line in File.ReadAllLines(fileName))
    {
        if ((!string.IsNullOrEmpty(line)) &&
            (!line.StartsWith(";")) &&
            (!line.StartsWith("#")) &&
            (!line.StartsWith("'")) &&
            (line.Contains('=')))
        {
            int index = line.IndexOf('=');
            string key = line.Substring(0, index).Trim();
            string value = line.Substring(index + 1).Trim();

            if ((value.StartsWith("\"") && value.EndsWith("\"")) ||
                (value.StartsWith("'") && value.EndsWith("'")))
            {
                value = value.Substring(1, value.Length - 2);
            }
            dictionary.Add(key, value);
        }
    }

    return dictionary;
}

Mais uma resposta (em janeiro de 2018) à antiga pergunta (em janeiro de 2009).

A especificação do arquivo de propriedades Java é descrita no Javadoc de java.util.properties.load (java.io.reader). Um problema é que a especificação é um pouco complicada do que a primeira impressão que podemos ter. Outro problema é que algumas respostas aqui adicionaram arbitrariamente especificações extras - por exemplo, ; e ' são considerados iniciantes de linhas de comentários, mas não deveriam ser. Citações duplas/únicas em torno dos valores das propriedades são removidas, mas não devem ser.

Os seguintes são pontos a serem considerados.

  1. Existem dois tipos de linha, linhas naturais e linhas lógicas.
  2. Uma linha natural é encerrada por \n, \r, \r\n ou o fim do fluxo.
  3. Uma linha lógica pode ser espalhada por várias linhas naturais adjacentes, escapando da sequência do terminador de linha com um caractere de barra de barragem \.
  4. Qualquer espaço em branco no início do segundo e seguindo linhas naturais em uma linha lógica é descartada.
  5. Espaços brancos são espaço (, \u0020), aba (\t, \u0009) e formar feed (\f, \u000C).
  6. Conforme declarado explicitamente na especificação, "Não é suficiente examinar apenas o caráter que precede uma sequência de terminador de linha para decidir se o terminador de linha está escapado; deve haver um número ímpar de barras de barriga contíguas para que o terminador de linha seja escape. Como a entrada é processada da esquerda para a direita , um número uniforme de zero de backslashes contíguas de 2N antes que um Terminator de linha (ou em outro lugar) codifique N backslashes após o processamento da fuga ".
  7. = é usado como o separador entre uma chave e um valor.
  8. : é usado como o separador entre uma chave e um valor também.
  9. O separador entre uma chave e um valor pode ser omitido.
  10. Uma linha de comentários tem # ou ! como seus primeiros personagens espaciais não brancos, o que significa que liderando espaços brancos antes # ou ! são autorizadas.
  11. Uma linha de comentários não pode ser estendida para as próximas linhas naturais, mesmo o terminador de linha é precedido por \.
  12. Conforme declarado explicitamente na especificação, =, : e os espaços brancos podem ser incorporados em uma chave se forem escapados por barras de barriga.
  13. Até os caracteres do terminador de linha podem ser incluídos usando \r e \n Sequências de fuga.
  14. Se um valor for omitido, uma sequência vazia será usada como um valor.
  15. \uxxxx é usado para representar um caractere unicode.
  16. Um caractere de barra de barragem antes que um caractere de fuga não válido não seja tratado como um erro; É soltado.

Então, por exemplo, se test.properties tem o seguinte conteúdo:

# A comment line that starts with '#'.
   # This is a comment line having leading white spaces.
! A comment line that starts with '!'.

key1=value1
  key2 : value2
    key3 value3
key\
  4=value\
    4
\u006B\u0065\u00795=\u0076\u0061\u006c\u0075\u00655
\k\e\y\6=\v\a\lu\e\6

\:\ \= = \\colon\\space\\equal

Deve ser interpretado como os seguintes pares de valor-chave.

+------+--------------------+
| KEY  | VALUE              |
+------+--------------------+
| key1 | value1             |
| key2 | value2             |
| key3 | value3             |
| key4 | value4             |
| key5 | value5             |
| key6 | value6             |
| : =  | \colon\space\equal |
+------+--------------------+

PropertiesLoader classe em Authlete.authlete O pacote NUGET pode interpretar o formato da especificação. O código de exemplo abaixo:

using System;
using System.IO;
using System.Collections.Generic;
using Authlete.Util;

namespace MyApp
{
    class Program
    {
        public static void Main(string[] args)
        {
            string file = "test.properties";
            IDictionary<string, string> properties;

            using (TextReader reader = new StreamReader(file))
            {
                properties = PropertiesLoader.Load(reader);
            }

            foreach (var entry in properties)
            {
                Console.WriteLine($"{entry.Key} = {entry.Value}");
            }
        }
    }
}

irá gerar esta saída:

key1 = value1
key2 = value2
key3 = value3
key4 = value4
key5 = value5
key6 = value6
: = = \colon\space\equal

Um exemplo equivalente em Java é o seguinte:

import java.util.*;
import java.io.*;

public class Program
{
    public static void main(String[] args) throws IOException
    {
        String file = "test.properties";
        Properties properties = new Properties();

        try (Reader reader = new FileReader(file))
        {
             properties.load(reader);
        }

        for (Map.Entry<Object, Object> entry : properties.entrySet())
        {
            System.out.format("%s = %s\n", entry.getKey(), entry.getValue());
        }    
    }
}

O código -fonte, PropertiesLoader.cs, pode ser encontrado em Authlete-cSharp. xunit testes para PropertiesLoader são escritos em PropertiesLoadestest.cs.

Sim, não há nenhuma aula embutida para fazer isso que estou ciente.

Mas esse não deveria ser um problema, deveria? Parece fácil o suficiente para analisar apenas armazenando o resultado de Stream.ReadToEnd() em uma string, dividindo com base em novas linhas e depois dividindo cada registro no = personagem. O que você restaria é um monte de pares de valor -chave que você pode facilmente lançar em um dicionário.

Aqui está um exemplo que pode funcionar para você:

public static Dictionary<string, string> GetProperties(string path)
{
    string fileData = "";
    using (StreamReader sr = new StreamReader(path))
    {
        fileData = sr.ReadToEnd().Replace("\r", "");
    }
    Dictionary<string, string> Properties = new Dictionary<string, string>();
    string[] kvp;
    string[] records = fileData.Split("\n".ToCharArray());
    foreach (string record in records)
    {
        kvp = record.Split("=".ToCharArray());
        Properties.Add(kvp[0], kvp[1]);
    }
    return Properties;
}

Aqui está um exemplo de como usá -lo:

Dictionary<string,string> Properties = GetProperties("data.txt");
Console.WriteLine("Hello: " + Properties["Hello"]);
Console.ReadKey();

A resposta real é não (pelo menos não por si só). Você ainda pode escrever seu próprio código para fazê -lo.

C# geralmente usa arquivos de configuração baseados em XML em vez do arquivo *.ini como você disse, então não há nada embutido para lidar com isso. No entanto, o Google retorna um número de resultados promissores.

Não conheço nenhuma maneira interna de fazer isso. No entanto, parece fácil de fazer, já que os únicos delimitadores com os quais você precisa se preocupar são o personagem de nova linha e o sinal de igual.

Seria muito fácil escrever uma rotina que retornará uma NameValuEcollection ou um idicicionário, dado o conteúdo do arquivo.

Você também pode usar a sintaxe da propriedade automática C# com valores padrão e um conjunto restritivo. A vantagem aqui é que você pode ter qualquer tipo de tipo de dados em suas propriedades "arquivo" (agora realmente uma classe). A outra vantagem é que você pode usar a sintaxe da propriedade C# para invocar as propriedades. No entanto, você só precisa de algumas linhas para cada propriedade (uma na declaração de propriedade e outra no construtor) para fazer isso funcionar.

using System;
namespace ReportTester {
   class TestProperties
   {
        internal String ReportServerUrl { get; private set; }
        internal TestProperties()
        {
            ReportServerUrl = "http://myhost/ReportServer/ReportExecution2005.asmx?wsdl";
        }
   }
}

Existem vários pacotes Nuget para isso, mas todos estão atualmente na versão pré-lançamento.

Atualização] em junho de 2018, Capgemini.cauldron.core.javaproperties está agora em uma versão estável (versão 2.1.0 e 3.0.20).

Percebo que isso não é exatamente o que você está perguntando, mas apenas por precaução:

Quando você quer carregar um real Arquivo Java Properties, você precisará acomodar sua codificação. Os documentos Java Indique que a codificação é ISO 8859-1, que contém algumas sequências de fuga que você pode não interpretar corretamente. Por exemplo, veja isso responde Para ver o que é necessário para transformar o UTF-8 em ISO 8859-1 (e vice-versa)

Quando precisávamos fazer isso, encontramos uma fonte aberta PropertyFile.cs e fez algumas alterações para apoiar as seqüências de fuga. Esta aula é boa para cenários de leitura/gravação. Você precisará do apoio PropertyFileIterator.cs classe também.

Mesmo se você não estiver carregando as verdadeiras propriedades Java, verifique se o seu arquivo de suporte pode expressar todos os personagens que você precisa salvar (pelo menos UTF-8)

Existe a solução exata do que você deseja. Por favor, encontre o artigo de aqui

Seu código tem vários pontos fortes em relação à eficiência.

  1. O aplicativo não carrega o arquivo de texto em todas as solicitações. Ele carrega o arquivo de texto apenas uma vez na memória. Para a solicitação subsequente, ele retorna o valor diretamente da memória. Isso é muito mais eficiente se o seu arquivo de texto contiver milhares ou mais pares de valor-chave.
  2. Qualquer alteração no arquivo de texto não requer reinicialização do aplicativo. Um observador do sistema de arquivos foi usado para acompanhar o estado do arquivo. Se mudar, aciona um evento e carrega as novas alterações de acordo com a memória para que você possa alterar o arquivo de texto em um aplicativo/editor de texto e ver o efeito alterado no aplicativo da Web.
  3. Você não pode apenas usá -lo em um aplicativo da Web, mas também pode usá -lo em qualquer aplicativo de desktop.

Obrigado. Tenha um bom dia.

Não, não existe: mas criei uma classe fácil de ajudar:

public class PropertiesUtility
{
    private static Hashtable ht = new Hashtable();
    public void loadProperties(string path)
    {
        string[] lines = System.IO.File.ReadAllLines(path);
        bool readFlag = false;
        foreach (string line in lines)
        {
            string text = Regex.Replace(line, @"\s+", "");
            readFlag =  checkSyntax(text);
            if (readFlag)
            {
                string[] splitText = text.Split('=');
                ht.Add(splitText[0].ToLower(), splitText[1]);
            }
        }
    }

    private bool checkSyntax(string line)
    {
        if (String.IsNullOrEmpty(line) || line[0].Equals('['))
        {
            return false;
        }

        if (line.Contains("=") && !String.IsNullOrEmpty(line.Split('=')[0]) && !String.IsNullOrEmpty(line.Split('=')[1]))
        {
            return true;
        }
        else
        {
            throw new Exception("Can not Parse Properties file please verify the syntax");
        }
    }

    public string getProperty(string key)
    {
        if (ht.Contains(key))
        {
            return ht[key].ToString();
        }
        else
        {
            throw new Exception("Property:" + key + "Does not exist");
        }

    }
}

Espero que isto ajude.

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