it-swarm.com.de

Kann .NET eine Eigenschaftsdatei laden und analysieren, die der Java-Eigenschaftenklasse entspricht?

Gibt es eine einfache Möglichkeit in C #, eine Eigenschaftendatei zu lesen, in der sich jede Eigenschaft in einer separaten Zeile befindet, gefolgt von einem Gleichheitszeichen und dem Wert, z. B .:

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

In Java kann die Properties-Klasse diese Analyse problemlos durchführen:

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

Ich kann die Datei problemlos in C # laden und jede Zeile analysieren, aber gibt es eine Möglichkeit, eine Eigenschaft zu erhalten, ohne den Schlüsselnamen und das Gleichheitszeichen selbst analysieren zu müssen? Die C # -Informationen, die ich gefunden habe, scheinen immer XML zu bevorzugen, aber dies ist eine vorhandene Datei, die ich nicht kontrolliere, und ich würde es vorziehen, sie in dem vorhandenen Format zu behalten, da es mehr Zeit braucht, um ein anderes Team in XML umzuwandeln als die vorhandene Datei zu analysieren.

49
Tai Squared

Nein, dafür gibt es keine integrierte Unterstützung.

Sie müssen Ihren eigenen "INIFileReader" erstellen. Vielleicht etwas in der Art?

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

Bearbeiten: Aktualisiert, um den Kommentar von Paul zu berücksichtigen. 

38
Jesper Palm

Die meisten ".properties" -Dateien von Java können aufgeteilt werden, wenn das Trennzeichen "=" verwendet wird. Das Format ist jedoch wesentlich komplizierter und ermöglicht das Einbetten von Leerzeichen, Gleichheitszeichen, Zeilenumbrüchen und beliebigen Unicode-Zeichen in den Eigenschaftsnamen oder Wert.

Ich musste einige Java-Eigenschaften für eine C # -Anwendung laden, sodass ich JavaProperties.cs implementiert habe, um ".properties" -Dateien mit derselben Vorgehensweise wie die Java-Version korrekt zu lesen und zu schreiben. Sie finden sie unter http: // www .kajabity.com/index.php/2009/06/loading-Java-properties-files-in-csharp/ .

Dort finden Sie eine ZIP-Datei mit der C # -Quelle für die Klasse und einige Beispieleigenschaftsdateien, mit denen ich sie getestet habe.

Genießen!

18
Kajabity

Letzte Klasse Danke @ 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 { }
            }
        }
    }


}

Verwendungsbeispiel:

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

Ich habe eine Methode geschrieben, die das Erstellen von Zeilen und das Angeben von Zeilen in der Datei ermöglicht.

Beispiele:

var1 = "value1" 
var2 = 'value2'

'var3 = ausgefallen 
; var4 = auch auskommentiert

Hier ist die Methode:

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

Noch eine Antwort (im Januar 2018) auf die alte Frage (im Januar 2009).

Die Spezifikation von Java properties file ist im JavaDoc von Java.util.Properties.load(Java.io.Reader) beschrieben. Ein Problem ist, dass die Spezifikation etwas komplizierter ist als der erste Eindruck, den wir haben könnten. Ein anderes Problem ist Einige Antworten hier haben willkürlich zusätzliche Spezifikationen hinzugefügt - zum Beispiel ; und ' werden als Starter von Kommentarzeilen angesehen, sollten dies aber nicht sein nicht sein.

Folgendes ist zu beachten.

  1. Es gibt zwei Arten von Linien, natürliche Linien und logische Linien .
  2. Eine natürliche Zeile wird mit \n, \r, \r\n Oder dem Ende des Streams abgeschlossen.
  3. Eine logische Zeile kann auf mehrere benachbarte natürliche Zeilen verteilt werden, indem der Zeilenabschluss mit einem Backslash-Zeichen \ Maskiert wird.
  4. Alle Leerzeichen am Anfang der zweiten und der folgenden natürlichen Zeilen in einer logischen Zeile werden verworfen.
  5. Leerzeichen sind Leerzeichen (, \u0020), Tabulatoren (\t, \u0009) Und Formularvorschübe (\f, \u000C).
  6. Wie in der Spezifikation explizit angegeben, "ist es nicht ausreichend, nur das Zeichen vor einer Zeilenendezeichenfolge zu untersuchen, um zu entscheiden, ob das Zeilenendezeichen maskiert wird. Es muss eine ungerade Anzahl von zusammenhängenden Backslashes für vorhanden sein Da die Eingabe von links nach rechts verarbeitet wird, codiert eine ungerade Zahl von 2n zusammenhängenden Backslashes vor einem Zeilenendezeichen (oder anderswo) nach der Escape-Verarbeitung n Backslashes. "
  7. = Wird als Trennzeichen zwischen einem Schlüssel und einem Wert verwendet.
  8. : Wird auch als Trennzeichen zwischen einem Schlüssel und einem Wert verwendet.
  9. Das Trennzeichen zwischen einem Schlüssel und einem Wert kann weggelassen werden.
  10. In einer Kommentarzeile ist # Oder ! Als erstes Zeichen ohne Leerzeichen angegeben, dh führende Leerzeichen vor # Oder ! Sind zulässig.
  11. Eine Kommentarzeile kann nicht auf die nächsten natürlichen Zeilen erweitert werden, auch wenn vor dem Zeilenende \ Steht.
  12. Wie in der Spezifikation ausdrücklich angegeben, können =, : Und Leerzeichen in einen Schlüssel eingebettet werden, wenn sie durch Backslashes maskiert werden.
  13. Sogar Zeilenabschlusszeichen können mit den Escape-Sequenzen \r Und \n Eingefügt werden.
  14. Wenn ein Wert weggelassen wird, wird eine leere Zeichenfolge als Wert verwendet.
  15. \uxxxx Wird verwendet, um ein Unicode-Zeichen darzustellen.
  16. Ein Backslash-Zeichen vor einem ungültigen Escape-Zeichen wird nicht als Fehler behandelt. es wird lautlos fallen gelassen.

Wenn also beispielsweise test.properties Den folgenden Inhalt hat:

# 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

es sollte als die folgenden Schlüssel-Wert-Paare interpretiert werden.

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

PropertiesLoader Klasse in Authlete.Authlete NuGet-Paket kann das Format der Spezifikation interpretieren. Der folgende Beispielcode:

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

erzeugt diese Ausgabe:

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

Ein äquivalentes Beispiel in Java lautet wie folgt:

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

Der Quellcode PropertiesLoader.cs Befindet sich in authlete-csharp . xUnit Tests für PropertiesLoader werden in PropertiesLoaderTest.cs geschrieben.

5

Ja, es gibt keine eingebauten Klassen, die mir bekannt sind.

Aber das sollte nicht wirklich ein Problem sein, oder? Es scheint einfach genug zu parsen, indem einfach das Ergebnis von Stream.ReadToEnd() in einer Zeichenfolge gespeichert wird, die auf der Grundlage neuer Zeilen aufgeteilt und dann jeder Datensatz nach dem Zeichen = aufgeteilt wird. Was übrig bleibt, ist eine Reihe von Schlüsselwertpaaren, die Sie leicht in ein Wörterbuch werfen können.

Hier ist ein Beispiel, das für Sie funktionieren könnte:

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

Hier ist ein Beispiel, wie man es benutzt:

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

Die eigentliche Antwort lautet nein (zumindest nicht für sich). Sie können immer noch Ihren eigenen Code dafür schreiben.

2
Carl Thronson

C # verwendet im Allgemeinen XML-basierte Konfigurationsdateien und nicht die * .ini-Datei, wie Sie es gesagt haben. Daher ist nichts eingebaut, um dies zu handhaben. Google liefert jedoch eine Anzahl vielversprechender Ergebnisse .

1
Joel Coehoorn

Ich kenne keinen eingebauten Weg, dies zu tun. Es scheint jedoch leicht genug, dies zu tun, da Sie sich nur um das Trennzeichen und das Gleichheitszeichen kümmern müssen.

Es ist sehr einfach, eine Routine zu schreiben, die eine NameValueCollection oder ein IDictionary mit dem Inhalt der Datei zurückgibt.

1
casperOne

Sie können auch die automatische Eigenschaftssyntax von C # mit Standardwerten und einem restriktiven Satz verwenden. Der Vorteil hier ist, dass Sie in Ihrer Eigenschaftsdatei "file" (jetzt eigentlich eine Klasse) einen beliebigen Datentyp haben können. Der andere Vorteil ist, dass Sie die Eigenschaften mit der C # -Eigenschaftssyntax aufrufen können. Sie benötigen jedoch nur ein paar Zeilen für jede Eigenschaft (eine in der Eigenschaftendeklaration und eine im Konstruktor), damit dies funktioniert.

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

Hierfür gibt es mehrere NuGet-Pakete, die sich jedoch derzeit in der Vorabversion befinden.

[Update] Ab Juni 2018 ist Capgemini.Cauldron.Core.JavaProperties jetzt in einer stabilen Version (Version 2.1.0 und 3.0.20).

1
Mike Rosoft

Nein, gibt es nicht: Aber ich habe eine einfache Klasse erstellt, um zu helfen: 

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

    }
}

Hoffe das hilft.

0
ApGokani

Mir ist klar, dass dies nicht genau das ist, was Sie fragen, aber nur für den Fall:

Wenn Sie eine Java-Eigenschaftendatei actual laden möchten, müssen Sie deren Kodierung berücksichtigen. The Java docs zeigt an, dass die Kodierung ISO 8859-1 ist, die einige Escape-Sequenzen enthält, die Sie möglicherweise nicht richtig interpretieren. Sehen Sie sich zum Beispiel diese SO Antwort an, um zu sehen, was notwendig ist, um UTF-8 in ISO 8859-1 (und umgekehrt) umzuwandeln.

Als wir dies tun mussten, fanden wir ein Open-Source-Objekt PropertyFile.cs und nahmen einige Änderungen vor, um die Escape-Sequenzen zu unterstützen. Diese Klasse eignet sich gut für Lese- und Schreibszenarien. Sie benötigen auch die unterstützende Klasse PropertyFileIterator.cs .

Wenn Sie keine echten Java-Eigenschaften laden, stellen Sie sicher, dass Ihre Prop-Datei alle Zeichen enthalten kann, die Sie zum Speichern benötigen (mindestens UTF-8).

0
Steve Eisner

Es gibt die genaue Lösung von dem, was Sie wollen. Den Artikel finden Sie unter hier

sein Code hat eine Reihe von Stärken bezüglich Effizienz.

  1. Die Anwendung lädt die Textdatei nicht bei jeder Anforderung. Es lädt die Textdatei nur einmal in den Speicher. Für die nachfolgende -Anforderung gibt es den Wert direkt aus dem Speicher zurück. Dies ist um ein Vielfaches effizienter, wenn Ihre Textdatei Tausende oder mehr Schlüsselwerte enthält.
  2. Bei jeder Änderung der Textdatei ist kein Neustart der Anwendung erforderlich. Ein Dateisystem-Watcher wurde verwendet, um den Dateizustand zu verfolgen . Wenn er sich ändert, löst er ein Ereignis aus und lädt die neuen Änderungen Entsprechend in den Arbeitsspeicher, sodass Sie die Textdatei ändern können einen Anwendung/Texteditor und sehen den geänderten Effekt in der Web Anwendung.
  3. Sie können es nicht nur in einer Webanwendung verwenden, sondern auch in einer beliebigen Desktopanwendung.

Vielen Dank. Einen schönen Tag noch.

0
arefinsami