web-dev-qa-db-fra.com

Est-ce que .NET peut charger et analyser un fichier de propriétés équivalent à la classe de propriétés Java?

Existe-t-il un moyen simple en C # de lire un fichier de propriétés contenant chaque propriété sur une ligne distincte suivie d'un signe égal et de la valeur, comme suit:

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

En Java, la classe Properties gère facilement cette analyse:

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

Je peux facilement charger le fichier en C # et analyser chaque ligne, mais existe-t-il un moyen intégré pour obtenir facilement une propriété sans avoir à analyser le nom de clé et le signe égal à signer moi-même? Les informations C # que j'ai trouvées semblent toujours privilégier XML, mais il s'agit d'un fichier existant que je ne contrôle pas et que je préférerais conserver dans son format actuel, car il faudra plus de temps pour demander à une autre équipe de le changer en XML. que l'analyse du fichier existant.

49
Tai Squared

Non, il n'y a pas de support intégré pour cela.

Vous devez créer votre propre "INIFileReader". Peut-être quelque chose comme ça?

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

Edit: mis à jour pour refléter le commentaire de Paul. 

38
Jesper Palm

La plupart des fichiers Java ".properties" peuvent être scindés en supposant que "=" est le séparateur - mais le format est beaucoup plus compliqué que cela et permet l’incorporation d’espaces, d’égal, de nouvelle ligne et de tout caractère Unicode dans le nom ou la valeur de la propriété.

J'avais besoin de charger certaines propriétés Java pour une application C # et j'ai donc implémenté JavaProperties.cs pour lire et écrire correctement les fichiers au format ".properties" en utilisant la même approche que la version Java - vous pouvez le trouver à l'adresse http: // www. .kajabity.com/index.php/2009/06/loading-Java-properties-files-in-csharp/ .

Vous y trouverez un fichier Zip contenant la source C # de la classe et des exemples de fichiers de propriétés avec lesquels je l’ai testé.

Prendre plaisir!

18
Kajabity

Classe finale. Merci @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 { }
            }
        }
    }


}

Exemple d'utilisation:

//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()
16
Nick Rimmer

J'ai écrit une méthode qui permet de créer des lignes, de dépasser les citations et de les citer dans le fichier.

Exemples:

var1 = "valeur1" 
var2 = 'valeur2'

'var3 = dépassé 
.__; var4 = dépassé aussi

Voici la méthode:

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

Encore une autre réponse (en janvier 2018) à l'ancienne question (en janvier 2009).

La spécification du fichier de propriétés Java est décrite dans le JavaDoc de Java.util.Properties.load(Java.io.Reader). Un problème est que la spécification est un peu compliquée que la première impression que nous pouvons avoir. Un autre problème est que certaines réponses ici ont ajouté des spécifications supplémentaires de manière arbitraire - par exemple, ; et ' sont considérés comme des débuts de lignes de commentaire, mais ils ne devraient pas l'être. Les citations doubles/simples autour des valeurs de propriété sont supprimées, mais elles ne devraient pas l'être.

Les points suivants sont à prendre en compte.

  1. Il existe deux types de ligne, lignes naturelles et lignes logiques.
  2. Une ligne naturelle est terminée par \n, \r, \r\n ou la fin du flux.
  3. Une ligne logique peut être répartie sur plusieurs lignes naturelles adjacentes en échappant la séquence de terminaison de ligne avec une barre oblique inversée \.
  4. Tout espace blanc au début de la deuxième ligne et les lignes naturelles suivantes dans une ligne logique sont ignorées.
  5. Les espaces blancs sont l'espace (, \u0020), l'onglet (\t, \u0009) et le flux de formulaire (\f, \u000C).
  6. Comme indiqué explicitement dans la spécification, "il ne suffit pas d'examiner uniquement le caractère précédant une séquence de terminaison de ligne pour décider si le terminateur de ligne est échappé; il doit exister un nombre impair de barres obliques inverses contiguës pour que le terminateur de ligne soit échappé" Étant donné que l'entrée est traitée de gauche à droite, un nombre pair non nul de 2n barres obliques inverses contiguës avant qu'un terminateur de ligne (ou ailleurs) code n barres obliques inverses après le traitement d'échappement. "
  7. = sert de séparateur entre une clé et une valeur.
  8. : sert également de séparateur entre une clé et une valeur.
  9. Le séparateur entre une clé et une valeur peut être omis.
  10. Une ligne de commentaire a # ou ! en tant que son premier caractère d'espacement non blanc, ce qui signifie que les espaces avant le début de # ou ! sont autorisés.
  11. Une ligne de commentaire ne peut pas être étendue aux lignes naturelles suivantes même son terminateur de ligne est précédé de \.
  12. Comme indiqué explicitement dans la spécification, =, : et des espaces blancs peuvent être incorporés dans une clé s'ils sont masqués par des barres obliques inverses.
  13. Même les caractères de fin de ligne peuvent être inclus à l'aide des séquences d'échappement \r et \n.
  14. Si une valeur est omise, une chaîne vide est utilisée comme valeur.
  15. \uxxxx est utilisé pour représenter un caractère Unicode.
  16. Un caractère barre oblique inverse avant un caractère d'échappement non valide n'est pas traité comme une erreur; il est déposé silencieusement.

Ainsi, par exemple, si test.properties a le contenu suivant:

# 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

il devrait être interprété comme les paires clé-valeur suivantes.

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

PropertiesLoader class dans Le paquet Authlete.Authlete NuGet peut interpréter le format de la spécification. L'exemple de code ci-dessous:

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

va générer cette sortie:

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

Un exemple équivalent en Java est le suivant:

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

Le code source, PropertiesLoader.cs, se trouve dans authlete-csharp . xUnit tests pour PropertiesLoader sont écrits en PropertiesLoaderTest.cs.

4
Takahiko Kawasaki

Oui, je ne suis au courant d'aucune classe intégrée.

Mais cela ne devrait pas vraiment être un problème, non? Il semble assez facile d'analyser simplement en stockant le résultat de Stream.ReadToEnd() dans une chaîne, en le divisant en fonction de nouvelles lignes, puis en divisant chaque enregistrement sur le caractère =. Ce qui vous reste, c'est un tas de paires de valeurs clés que vous pouvez facilement mélanger dans un dictionnaire.

Voici un exemple qui pourrait fonctionner pour vous:

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

Voici un exemple d'utilisation:

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

La vraie réponse est non (du moins pas par elle-même). Vous pouvez toujours écrire votre propre code pour le faire.

2
Carl Thronson

C # utilise généralement des fichiers de configuration basés sur XML plutôt que le fichier de style * .ini comme vous l'avez dit, il n'y a donc rien de intégré pour gérer cela. Cependant, Google renvoie un nombre de résultats prometteurs .

1
Joel Coehoorn

Je ne connais aucun moyen intégré de faire cela. Cependant, cela semblerait assez facile à faire, puisque les seuls délimiteurs à prendre en compte sont le caractère de nouvelle ligne et le signe égal.

Il serait très facile d'écrire une routine qui renverra un NameValueCollection ou un IDictionary en fonction du contenu du fichier.

1
casperOne

Vous pouvez également utiliser la syntaxe de propriété automatique C # avec des valeurs par défaut et un ensemble restrictif. L'avantage ici est que vous pouvez avoir n'importe quel type de données dans vos propriétés "fichier" (maintenant une classe). L’autre avantage est que vous pouvez utiliser la syntaxe de propriété C # pour appeler les propriétés. Cependant, vous avez juste besoin de quelques lignes pour chaque propriété (une dans la déclaration de propriété et une dans le constructeur) pour que cela fonctionne.

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

Il existe plusieurs packages NuGet pour cela, mais tous sont actuellement en version préliminaire.

[Mise à jour] À compter de juin 2018, Capgemini.Cauldron.Core.JavaProperties est maintenant dans une version stable (versions 2.1.0 et 3.0.20).

1
Mike Rosoft

Non, il n'y en a pas: mais j'ai créé une classe facile pour vous aider: 

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

    }
}

J'espère que cela t'aides.

0
ApGokani

Je réalise que ce n'est pas exactement ce que vous demandez, mais juste au cas où:

Lorsque vous souhaitez charger un fichier de propriétés Java actual, vous devez adapter son codage. Les documents Java indiquent que le codage est ISO 8859-1, qui contient des séquences d'échappement que vous pourriez ne pas interpréter correctement. Par exemple, regardez cette réponse SO pour voir ce qui est nécessaire pour convertir l'UTF-8 en ISO 8859-1 (et vice versa)

Lorsque nous avons eu besoin de faire cela, nous avons trouvé un fichier open-source PropertyFile.cs et apporté quelques modifications pour prendre en charge les séquences d'échappement. Cette classe convient bien aux scénarios de lecture/écriture. Vous aurez également besoin de la classe PropertyFileIterator.cs class.

Même si vous ne chargez pas de vraies propriétés Java, assurez-vous que votre fichier prop peut exprimer tous les caractères que vous avez besoin de sauvegarder (au moins UTF-8).

0
Steve Eisner

Il y a la solution exacte de ce que vous voulez. s'il vous plaît trouver l'article de ici

son code a un tas de points forts en matière d'efficacité.

  1. L'application ne charge pas le fichier texte à chaque demande. Il Charge le fichier texte une seule fois dans la mémoire. Pour la demande ultérieure , Il renvoie la valeur directement à partir de la mémoire. Cela est beaucoup plus efficace si votre fichier texte contient des milliers ou plus de paires de clés.
  2. Toute modification dans le fichier texte ne nécessite pas de redémarrage de l'application. Un observateur du système de fichiers .__ a été utilisé pour suivre l’état du fichier . S'il change, il déclenche un événement et charge les nouvelles modifications .__ en conséquence dans la mémoire afin que vous puissiez modifier le fichier texte Un application/éditeur de texte et voir l'effet modifié dans l'application Web
  3. Vous êtes non seulement capable de l'utiliser dans une application Web, mais également de pouvoir l'utiliser dans n'importe quelle application de bureau.

Merci. Bonne journée.

0
arefinsami