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

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

Question

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, telle que la suivante :

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é d'obtenir facilement une propriété sans avoir à analyser moi-même le nom de la clé et le signe égal ?Les informations C# que j'ai trouvées semblent toujours favoriser XML, mais il s'agit d'un fichier existant que je ne contrôle pas et je préférerais le conserver dans le format existant car il faudra plus de temps pour qu'une autre équipe le change en XML. que d'analyser le fichier existant.

Était-ce utile?

La solution

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

Vous devez créer votre propre " INIFileReader " ;. Peut-être que 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"]);

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

Autres conseils

La plupart des Java ". .properties " les fichiers peuvent être divisés en supposant que " = " est le séparateur - mais le format est bien plus compliqué que cela et permet d’incorporer des espaces, des équivalents, des lignes nouvelles et tous les caractères Unicode dans le nom ou la valeur de la propriété.

Je devais charger certaines propriétés Java pour une application C #, j'ai donc implémenté JavaProperties.cs pour lire et écrire correctement " .properties " fichiers formatés utilisant la même approche que la version Java - vous pouvez le trouver à 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é.

Profitez!

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

J'ai écrit une méthode qui permet de séparer les lignes et les guillemets 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;
}

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 amorceurs 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 ne doivent pas l'être.

Les points suivants sont à prendre en compte.

  1. Il existe deux types de ligne, les lignes naturelles et les 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 inverse \.
  4. Tous les espaces au début de la deuxième ligne et les lignes naturelles suivantes d'une ligne logique sont ignorées.
  5. Les espaces sont l’espace (, \u0020), l’onglet (\t, \u0009) et le fil d’alimentation (\f, \u000C).
  6. Comme indiqué explicitement dans la spécification, & "il ne suffit pas d’examiner 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 y avoir un nombre impair de barres obliques inverses contiguës pour que le terminateur de ligne soit échappé. Etant 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 pour n barres obliques inverses après le traitement d'échappement. & Quot;
  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 ! comme premier caractère d'espacement non blanc, ce qui signifie que les espaces précédant \uxxxx ou test.properties 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 PropertiesLoader.
  12. Comme indiqué explicitement dans la spécification, PropertiesLoader.cs, PropertiesLoaderTest.cs et des espaces peuvent être incorporés dans une clé s'ils sont échappés par des barres obliques inverses.
  13. Même les caractères de fin de ligne peuvent être inclus à l'aide de <=> et <=> séquences d'échappement.
  14. Si une valeur est omise, une chaîne vide est utilisée comme valeur.
  15. <=> 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 supprimé silencieusement.

Ainsi, par exemple, si <=> 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 doit ê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 |
+------+--------------------+

<=> classe dans Authlete.Authlete Le package NuGet peut interpréter le format du fichier. 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}");
            }
        }
    }
}

générera 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, <=>, se trouve dans authlete-csharp . Les tests xUnit pour <=> sont écrits entre <=>.

Oui, il n'y a pas de classes intégrées à faire que je sache.

Mais cela ne devrait pas vraiment être un problème, non? Il semble assez facile d'analyser simplement en enregistrant le résultat de Stream.ReadToEnd() dans une chaîne, en effectuant une division 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 jeter 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();

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

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 d'intégré pour gérer cela. Toutefois, Google renvoie un nombre de résultats prometteurs .

Je ne connais aucun moyen intégré de procéder. 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.

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 alors avoir n'importe quel type de données dans vos propriétés & Quot; fichier & Quot; (maintenant en fait une classe). L’autre avantage est que vous pouvez utiliser la syntaxe de propriété C # pour appeler les propriétés. Cependant, il suffit 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";
        }
   }
}

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

MISE À JOUR] En juin 2018, Capgemini.Cauldron.Core.JavaProperties est désormais en version stable (version 2.1.0 et 3.0.20).

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 réel , vous devez adapter son codage. Les documents Java indiquent que les documents Java Le codage est ISO 8859-1, qui contient des séquences d'échappement que vous pourriez ne pas interpréter correctement. Par exemple, consultez la cette réponse SO pour savoir ce qui se passe nécessaire de convertir UTF-8 en ISO 8859-1 (et inversement)

Lorsque nous avons eu besoin de le faire, nous avons trouvé un 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 besoin de la PropertyFileIterator.cs , ainsi de la prise en charge correspondante

.

Même si vous ne chargez pas de véritables propriétés Java, assurez-vous que votre fichier prop peut exprimer tous les caractères que vous devez enregistrer (au moins au format UTF-8)

Il y a la solution exacte de ce que vous voulez. Veuillez trouver l'article dans ici

Ce code présente de nombreux points forts en matière d’efficacité.

  1. L'application ne charge pas le fichier texte dans chaque requête. Il charge le fichier texte une seule fois dans la mémoire. Pour la suite request, il renvoie la valeur directement à partir de la mémoire. C'est beaucoup plus efficace si votre fichier texte contient des milliers ou plus paires clé-valeur.
  2. Toute modification dans le fichier texte ne nécessite pas de redémarrage de l'application. UNE L’observateur du système de fichiers a été utilisé pour suivre l’état du fichier. Si cela change, il déclenche un événement et charge les nouvelles modifications conformément à la mémoire de sorte que vous pouvez modifier le fichier texte en un application / éditeur de texte et voir l'effet modifié sur le Web application.
  3. Vous pouvez non seulement l'utiliser dans une application Web, mais également de l'utiliser dans n'importe quelle application de bureau.

Merci. Passez une bonne journée.

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 vous aidera.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top