65 votes

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

Existe-t-il un moyen simple en C# de lire un fichier de propriétés dont chaque propriété se trouve sur une ligne distincte, suivie d'un signe égal et de la valeur, comme dans le cas suivant :

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

En Java, la classe Propriétés gère facilement cette analyse syntaxique :

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 privilégier le 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 sera plus long de demander à une autre équipe de le modifier en XML que d'analyser le fichier existant.

49voto

Jesper Palm Points 5280

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

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

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.

19voto

Nick Rimmer Points 41

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

}

Utilisation d'un échantillon :

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

18voto

La plupart des fichiers ".properties" de Java peuvent être divisés en supposant que le "=" est le séparateur - mais le format est beaucoup plus compliqué que cela et permet d'incorporer des espaces, des égalités, des nouvelles lignes et 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#. J'ai donc implémenté JavaProperties.cs pour lire et écrire correctement des fichiers au format ".properties" en utilisant la même approche que la version Java - vous pouvez la trouver à l'adresse suivante 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 quelques exemples de fichiers de propriétés avec lesquels je l'ai testée.

Profitez-en !

8voto

eXXL Points 623

J'ai écrit une méthode qui permet d'émoter des lignes, de commenter et de citer à l'intérieur du fichier.

Exemples :

var1="valeur1"
var2='valeur2'

var3=outcommenté
;var4=outcommenté, 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;
}

3voto

Spencer Ruport Points 24589

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

Mais ça ne devrait pas vraiment être un problème, n'est-ce pas ? Il semble assez facile de l'analyser en stockant simplement le résultat de Stream.ReadToEnd() dans une chaîne de caractères, le fractionnement sur la base de nouvelles lignes, puis le fractionnement de chaque enregistrement sur la chaîne de caractères. = caractère. Vous vous retrouveriez alors avec un tas de paires clé-valeur que vous pourriez facilement placer dans un dictionnaire.

Voici un exemple qui pourrait vous convenir :

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X