.NET può caricare e analizzare un file delle proprietà equivalente alla classe Proprietà Java?

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

Domanda

Esiste un modo semplice in C# per leggere un file delle proprietà che ha ciascuna proprietà su una riga separata seguita da un segno di uguale e dal valore, come il seguente:

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

In Java, la classe Properties gestisce facilmente questa analisi:

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

Posso caricare facilmente il file in C# e analizzare ogni riga, ma esiste un modo integrato per ottenere facilmente una proprietà senza dover analizzare il nome della chiave e il segno di uguale?Le informazioni C# che ho trovato sembrano sempre favorire XML, ma questo è un file esistente che non controllo e preferirei mantenerlo nel formato esistente poiché richiederà più tempo per convincere un altro team a modificarlo in XML piuttosto che analizzare il file esistente.

È stato utile?

Soluzione

No, non esiste un supporto integrato per questo.

Devi creare il tuo " INIFileReader " ;. Forse qualcosa del genere?

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

Modifica: aggiornato per riflettere il commento di Paul.

Altri suggerimenti

Most Java " .properties " i file possono essere divisi assumendo il " = " è il separatore, ma il formato è significativamente più complicato di così e consente di incorporare spazi, uguali, newline e qualsiasi carattere Unicode nel nome o nel valore della proprietà.

Avevo bisogno di caricare alcune proprietà Java per un'applicazione C #, quindi ho implementato JavaProperties.cs per leggere e scrivere correttamente " .properties " file formattati usando lo stesso approccio della versione Java - puoi trovarli su http://www.kajabity.com/index.php/2009/06/loading-java-properties-files-in-csharp/ .

Qui troverai un file zip contenente l'origine C # per la classe e alcuni file di proprietà di esempio con cui l'ho provato.

Enjoy!

Classe finale. Grazie @ 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 di esempio:

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

Ho scritto un metodo che consente linee emty, outcommenting e quoting all'interno del file.

Esempi:

&

var1 = quot; & Valore1 quot;
VAR2 = 'valore2'

'var3 = outcommented
; var4 = anche outcommented

Ecco il metodo:

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

Ancora un'altra risposta (a gennaio 2018) alla vecchia domanda (a gennaio 2009).

La specifica del file delle proprietà Java è descritta nel JavaDoc di java.util.Properties.load(java.io.Reader). Un problema è che le specifiche sono un po 'complicate rispetto alla prima impressione che possiamo avere. Un altro problema è che alcune risposte qui hanno aggiunto arbitrariamente ulteriori specifiche - ad esempio, ; e ' sono considerate come antipasti di righe di commento ma non dovrebbero esserlo. Le virgolette doppie / singole intorno ai valori delle proprietà vengono rimosse ma non dovrebbero esserlo.

I seguenti sono punti da considerare.

  1. Esistono due tipi di linea, linee naturali e linee logiche .
  2. Una linea naturale è terminata da \n, \r, \r\n o dalla fine dello stream.
  3. Una linea logica può essere distribuita su più linee naturali adiacenti sfuggendo alla sequenza del terminatore di riga con un carattere barra rovesciata \.
  4. Qualsiasi spazio bianco all'inizio della seconda e seguendo le linee naturali in una linea logica viene scartato.
  5. Gli spazi bianchi sono spazio (, \u0020), scheda (\t, \u0009) e feed del modulo (\f, \u000C).
  6. Come indicato esplicitamente nelle specifiche, " non è sufficiente esaminare solo il carattere che precede una sequenza di terminatori di linea per decidere se il terminatore di linea è sfuggito; ci deve essere un numero dispari di barre rovesciate contigue per il escape del terminatore di linea. Poiché l'input viene elaborato da sinistra a destra, un numero pari pari a zero pari a 2n barre rovesciate contigue prima che un terminatore di riga (o altrove) codifichi n barre rovesciate dopo l'elaborazione di escape. & Quot;
  7. = viene utilizzato come separatore tra una chiave e un valore.
  8. : viene utilizzato anche come separatore tra una chiave e un valore.
  9. Il separatore tra una chiave e un valore può essere omesso.
  10. Una riga di commento ha # o ! come primi caratteri non bianchi, il che significa che sono consentiti spazi bianchi iniziali prima di \uxxxx o test.properties.
  11. Una riga di commento non può essere estesa alle righe naturali successive anche se il suo terminatore di riga è preceduto da PropertiesLoader.
  12. Come indicato esplicitamente nelle specifiche, PropertiesLoader.cs, PropertiesLoaderTest.cs e gli spazi bianchi possono essere incorporati in una chiave se sono sfuggiti a barre rovesciate.
  13. È possibile includere anche caratteri di terminazione di riga utilizzando <=> e <=> sequenze di escape.
  14. Se un valore viene omesso, viene utilizzata una stringa vuota come valore.
  15. <=> è usato per rappresentare un carattere Unicode.
  16. Un carattere barra rovesciata prima di un carattere di escape non valido non viene trattato come un errore; viene lasciato cadere silenziosamente.

Quindi, ad esempio, se <=> ha il seguente contenuto:

# 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

dovrebbe essere interpretato come le seguenti coppie chiave-valore.

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

<=> classe nel Authlete.Authlete Il pacchetto NuGet può interpretare il formato del specifica. Il seguente codice di esempio:

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

genererà questo output:

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

Un esempio equivalente in Java è il seguente:

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

Il codice sorgente, <=>, è disponibile in authlete-csharp . xUnit i test per <=> sono scritti in <=>.

Sì, non ci sono classi integrate per fare ciò di cui sono a conoscenza.

Ma non dovrebbe davvero essere un problema, vero? Sembra abbastanza facile da analizzare semplicemente memorizzando il risultato di Stream.ReadToEnd() in una stringa, suddividendolo in base a nuove righe e quindi suddividendo ciascun record sul carattere =. Ciò che ti rimarrebbe è un gruppo di coppie chiave-valore che puoi facilmente gettare in un dizionario.

Ecco un esempio che potrebbe funzionare per te:

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

Ecco un esempio di come usarlo:

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

La vera risposta è no (almeno non da sola). Puoi ancora scrivere il tuo codice per farlo.

C # usa generalmente i file di configurazione basati su XML piuttosto che il file in stile * .ini come hai detto, quindi non c'è niente incorporato per gestirlo. Tuttavia, google restituisce un numero di risultati promettenti .

Non conosco alcun modo integrato per farlo. Tuttavia, sembrerebbe abbastanza facile da fare, poiché gli unici delimitatori di cui devi preoccuparti sono il carattere di nuova riga e il segno di uguale.

Sarebbe molto semplice scrivere una routine che restituirà un NameValueCollection o un IDictionary dato il contenuto del file.

Puoi anche usare la sintassi automatica delle proprietà C # con valori predefiniti e un set restrittivo. Il vantaggio qui è che puoi avere qualsiasi tipo di tipo di dati nelle tue proprietà & Quot; file & Quot; (ora in realtà una classe). L'altro vantaggio è che è possibile utilizzare la sintassi della proprietà C # per richiamare le proprietà. Tuttavia, hai solo bisogno di un paio di righe per ogni proprietà (una nella dichiarazione di proprietà e una nel costruttore) per farlo funzionare.

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

Esistono diversi pacchetti NuGet per questo, ma tutti sono attualmente in versione pre-rilascio.

AGGIORNAMENTO] A partire da giugno 2018, Capgemini.Cauldron.Core.JavaProperties è ora in una versione stabile (versione 2.1.0 e 3.0.20).

Mi rendo conto che questo non è esattamente quello che stai chiedendo, ma per ogni evenienza:

Quando si desidera caricare un file di proprietà Java effettivo , è necessario adattarne la codifica. I documenti Java indicano che il la codifica è ISO 8859-1, che contiene alcune sequenze di escape che potresti non interpretare correttamente. Ad esempio, guarda questa risposta SO per vedere cosa c'è necessario per trasformare UTF-8 in ISO 8859-1 (e viceversa)

Quando abbiamo dovuto farlo, abbiamo trovato un open source PropertyFile.cs e apportato alcune modifiche per supportare le sequenze di escape. Questa classe è buona per gli scenari di lettura / scrittura. Sarà necessaria anche la classe PropertyFileIterator.cs .

Anche se non stai caricando le proprietà Java reali, assicurati che il tuo file prop possa esprimere tutti i caratteri che devi salvare (almeno UTF-8)

C'è la soluzione esatta di ciò che vuoi. trova l'articolo di qui

il suo codice ha un sacco di punti di forza per quanto riguarda l'efficienza.

  1. L'applicazione non carica il file di testo in ogni richiesta. esso carica il file di testo solo una volta in memoria. Per il successivo richiesta, restituisce il valore direttamente dalla memoria. Questo è molto più efficiente se il tuo file di testo ne contiene migliaia o più coppie chiave-valore.
  2. Qualsiasi modifica nel file di testo non richiede il riavvio dell'applicazione. UN il file system watcher è stato usato per tenere traccia dello stato del file. Se cambia, attiva un evento e carica le nuove modifiche in base alla memoria in modo che, è possibile modificare il file di testo in uno editor di applicazioni / testi e vedere l'effetto modificato sul Web applicazione.
  3. Non sei solo in grado di usarlo in un'applicazione web ma anche in grado per usarlo in qualsiasi applicazione desktop.

Grazie. Buona giornata.

No non c'è: ma ho creato una classe semplice per aiutare:

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

    }
}

Spero che questo aiuti.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top