¿Puede .NET cargar y analizar un archivo de propiedades equivalente a la clase Propiedades de Java?

¿Hay alguna manera fácil en C # de leer un archivo de propiedades que tenga cada propiedad en una línea separada seguida de un signo igual y el valor, como el siguiente:

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

En Java, la clase de Propiedades maneja este análisis fácilmente:

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

Puedo cargar fácilmente el archivo en C # y analizar cada línea, pero ¿existe una forma integrada para obtener fácilmente una propiedad sin tener que analizar el nombre de la tecla y el signo igual por mí mismo? La información de C # que he encontrado parece favorecer siempre a XML, pero este es un archivo existente que no controlo y preferiría mantenerlo en el formato existente, ya que requerirá más tiempo para que otro equipo lo cambie a XML. que analizar el archivo existente.

No, no hay soporte integrado para esto.

Tienes que hacer tu propio “INIFileReader”. Tal vez algo como esto?

 var data = new Dictionary(); 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"]); 

Editar: actualizado para reflejar el comentario de Paul.

La mayoría de los archivos “.properties” de Java pueden dividirse suponiendo que “=” es el separador, pero el formato es mucho más complicado que eso y permite incrustar espacios, equivalentes, líneas nuevas y cualquier carácter Unicode en el nombre o valor de la propiedad.

Necesitaba cargar algunas propiedades Java para una aplicación C #, así que he implementado JavaProperties.cs para leer y escribir correctamente los archivos formateados “.properties” usando el mismo enfoque que la versión Java. Puede encontrarla en http: //www.kajabity .com / index.php / 2009/06 / carga-java-propiedades-archivos-en-csharp / .

Allí, encontrará un archivo zip que contiene la fuente de C # para la clase y algunos archivos de propiedades de muestra con los que lo probé.

¡Disfrutar!

Clase final Gracias @eXXL .

 public class Properties { private Dictionary 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(); 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 de muestra:

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

He escrito un método que permite emty lines, outcommenting y cotización dentro del archivo.

Ejemplos:

var1 = “value1”
var2 = ‘value2’

‘var3 = outcommented
; var4 = outcommented, también

Este es el método:

 public static IDictionary ReadDictionaryFile(string fileName) { Dictionary dictionary = new Dictionary(); 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; } 

Sí, no hay clases integradas para hacer esto que yo sepa.

Pero eso realmente no debería ser un problema ¿verdad? Parece bastante fácil analizar simplemente almacenando el resultado de Stream.ReadToEnd() en una cadena, dividiendo según nuevas líneas y luego dividiendo cada registro en el carácter = . Lo que te quedaría es un grupo de pares de valores clave que puedes lanzar fácilmente a un diccionario.

Aquí hay un ejemplo que podría funcionar para usted:

 public static Dictionary GetProperties(string path) { string fileData = ""; using (StreamReader sr = new StreamReader(path)) { fileData = sr.ReadToEnd().Replace("\r", ""); } Dictionary Properties = new Dictionary(); 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; } 

Aquí hay un ejemplo de cómo usarlo:

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

La respuesta real es no (al menos no solo). Aún puede escribir su propio código para hacerlo.

C # generalmente usa archivos de configuración basados ​​en xml en lugar del archivo de estilo * .ini como usted dijo, por lo que no hay nada incorporado para manejar esto. Sin embargo, google devuelve una cantidad de resultados prometedores .

No conozco ninguna forma incorporada de hacer esto. Sin embargo, parece bastante fácil de hacer, ya que los únicos delimitadores que tiene que preocuparse son el carácter de nueva línea y el signo de igual.

Sería muy fácil escribir una rutina que devolverá una NameValueCollection, o un IDictionary dado el contenido del archivo.

También puede usar la syntax de propiedad automática C # con valores predeterminados y un conjunto restrictivo. La ventaja aquí es que puede tener cualquier tipo de tipo de datos en el “archivo” de sus propiedades (ahora en realidad una clase). La otra ventaja es que puede usar la syntax de la propiedad C # para invocar las propiedades. Sin embargo, solo necesita un par de líneas para cada propiedad (una en la statement de propiedad y otra en el constructor) para que esto funcione.

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

Otra respuesta más (en enero de 2018) a la pregunta anterior (en enero de 2009).

La especificación del archivo de propiedades de Java se describe en JavaDoc de java.util.Properties.load(java.io.Reader) . Un problema es que la especificación es un poco más complicada que la primera impresión que podamos tener. Otro problema es que algunas respuestas aquí añadieron arbitrariamente especificaciones adicionales, por ejemplo ; y ' se consideran como iniciadores de líneas de comentarios, pero no deberían serlo. Las citas dobles / únicas alrededor de los valores de propiedad se eliminan, pero no deberían ser.

Los siguientes son puntos a considerar.

  1. Hay dos tipos de líneas, líneas naturales y líneas lógicas .
  2. Una línea natural termina con \n , \r , \r\n o al final de la secuencia.
  3. Una línea lógica puede extenderse a través de varias líneas naturales adyacentes al escapar de la secuencia del terminador de línea con un carácter de barra invertida \ .
  4. Cualquier espacio en blanco al comienzo de la segunda y siguientes líneas naturales en una línea lógica se descartan.
  5. Los espacios en blanco son espacio ( , \u0020 ), tab ( \t , \u0009 ) y feed de formulario ( \f , \u000C ).
  6. Tal como se establece explícitamente en la especificación, “no es suficiente examinar únicamente el carácter que precede a una secuencia de terminación de línea para decidir si se escapó el terminador de línea: debe haber un número impar de barras invertidas contiguas para el escape del terminador de línea. la entrada se procesa de izquierda a derecha, un número par distinto de cero de 2n barras diagonales contiguas antes de que un terminador de línea (u otro) codifique n barras diagonales inversas después del proceso de escape “.
  7. = se usa como el separador entre una clave y un valor.
  8. : se usa como el separador entre una clave y un valor, también.
  9. El separador entre una clave y un valor puede omitirse.
  10. ¡Una línea de comentario tiene # o ! como sus primeros caracteres espaciales no blancos, lo que significa espacios blancos iniciales antes de # o ! están permitidos.
  11. Una línea de comentario no se puede extender a las siguientes líneas naturales, incluso su terminador de línea está precedido por \ .
  12. Como se indica explícitamente en la especificación, = : y los espacios en blanco se pueden incrustar en una clave si se escapan por las barras diagonales inversas.
  13. Incluso los caracteres del terminador de línea se pueden incluir usando secuencias de escape \r \n .
  14. Si se omite un valor, se utiliza una cadena vacía como valor.
  15. \uxxxx se usa para representar un caracter Unicode.
  16. Una barra invertida antes de un carácter de escape no válido no se trata como un error; se deja caer en silencio.

Entonces, por ejemplo, si test.properties tiene el siguiente contenido:

 # 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 

debe interpretarse como los siguientes pares clave-valor.

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

PropertiesLoader clase PropertiesLoader en el paquete Authlete.Authlete NuGet puede interpretar el formato de la especificación. El código de ejemplo a continuación:

 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 properties; using (TextReader reader = new StreamReader(file)) { properties = PropertiesLoader.Load(reader); } foreach (var entry in properties) { Console.WriteLine($"{entry.Key} = {entry.Value}"); } } } } 

generará esta salida:

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

Un ejemplo equivalente en Java es el siguiente:

 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 entry : properties.entrySet()) { System.out.format("%s = %s\n", entry.getKey(), entry.getValue()); } } } 

El código fuente, PropertiesLoader.cs , se puede encontrar en authlete-csharp . Las pruebas xUnit para PropertiesLoader están escritas en PropertiesLoaderTest.cs .

Me doy cuenta de que esto no es exactamente lo que estás preguntando, pero por las dudas:

Cuando desee cargar un archivo de propiedades de Java real , deberá acomodar su encoding. Los documentos de Java indican que la encoding es ISO 8859-1, que contiene algunas secuencias de escape que podría no interpretar correctamente. Por ejemplo, mire esta respuesta SO para ver qué es necesario para convertir UTF-8 en ISO 8859-1 (y viceversa)

Cuando necesitábamos hacer esto, encontramos un PropertyFile.cs de código abierto e hicimos algunos cambios para admitir las secuencias de escape. Esta clase es buena para escenarios de lectura / escritura. Necesitarás también la clase Support Property FileIterator.cs.

Incluso si no está cargando propiedades verdaderas de Java, asegúrese de que su archivo prop pueda express todos los caracteres que necesita guardar (UTF-8 al menos)

Existe la solución exacta de lo que quieres. por favor encuentra el artículo de aquí

su código tiene muchos puntos fuertes con respecto a la eficiencia.

  1. La aplicación no carga el archivo de texto en cada solicitud. Carga el archivo de texto solo una vez en la memoria. Para la solicitud posterior, devuelve el valor directamente de la memoria. Esto es mucho más eficiente si su archivo de texto contiene miles o más pares clave-valor.
  2. Cualquier cambio en el archivo de texto no requiere el reinicio de la aplicación. Un vigilante del sistema de archivos se ha utilizado para realizar un seguimiento del estado del archivo. Si cambia, desencadena un evento y carga los nuevos cambios de acuerdo con la memoria, de modo que puede cambiar el archivo de texto en una aplicación / editor de texto y ver el efecto modificado en la aplicación web.
  3. No solo puede usarlo en una aplicación web, sino que también puede usarlo en cualquier aplicación de escritorio.

Gracias. Que tengas un buen día.

No, no; pero he creado una clase fácil para ayudar:

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

Espero que esto ayude.

Hay varios paquetes NuGet para esto, pero todos se encuentran actualmente en versión preliminar.

  • Capgemini.Cauldron.Core.JavaProperties 2.0.39-beta
  • Kajabity.Tools.Java 0.2.6638.28124

[Actualización] A partir de junio de 2018, Capgemini.Cauldron.Core.JavaProperties ahora se encuentra en una versión estable (versión 2.1.0 y 3.0.20).