简体   繁体   English

.NET可以加载和解析与Java Properties类等效的属性文件吗?

[英]Can .NET load and parse a properties file equivalent to Java Properties class?

Is there an easy way in C# to read a properties file that has each property on a separate line followed by an equals sign and the value, such as the following: 在C#中是否有一种简单的方法来读取属性文件,该文件在单独的行上包含每个属性,后跟等号和值,如下所示:

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

In Java, the Properties class handles this parsing easily: 在Java中,Properties类可以轻松处理此解析:

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

I can easily load the file in C# and parse each line, but is there a built in way to easily get a property without having to parse out the key name and equals sign myself? 我可以轻松地在C#中加载文件并解析每一行,但是有没有内置的方法来轻松获取属性而无需解析密钥名称和等号本身? The C# information I have found seems to always favor XML, but this is an existing file that I don't control and I would prefer to keep it in the existing format as it will require more time to get another team to change it to XML than parsing the existing file. 我发现的C#信息似乎总是支持XML,但这是一个我无法控制的现有文件,我宁愿将其保留为现有格式,因为需要更多时间让其他团队将其更改为XML而不是解析现有的文件。

No there is no built-in support for this. 没有内置的支持。

You have to make your own "INIFileReader". 你必须自己制作“INIFileReader”。 Maybe something like this? 也许是这样的?

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: Updated to reflect Paul's comment. 编辑:更新以反映保罗的评论。

Most Java ".properties" files can be split by assuming the "=" is the separator - but the format is significantly more complicated than that and allows for embedding spaces, equals, newlines and any Unicode characters in either the property name or value. 大多数Java“.properties”文件可以通过假设“=”是分隔符来拆分 - 但格式要比这复杂得多,并且允许在属性名称或值中嵌入空格,等号,换行符和任何Unicode字符。

I needed to load some Java properties for a C# application so I have implemented JavaProperties.cs to correctly read and write ".properties" formatted files using the same approach as the Java version - you can find it at http://www.kajabity.com/index.php/2009/06/loading-java-properties-files-in-csharp/ . 我需要为C#应用程序加载一些Java属性,所以我已经使用与Java版本相同的方法实现了JavaProperties.cs以正确读取和写入“.properties”格式化文件 - 您可以在http://www.kajabity找到它.com / index.php / 2009/06 / loading-java-properties-files-in-csharp /

There, you will find a zip file containing the C# source for the class and some sample properties files I tested it with. 在那里,你会找到一个zip文件,其中包含该类的C#源代码以及我测试过的一些示例属性文件。

Enjoy! 请享用!

Final class. 最后一堂课。 Thanks @eXXL . 谢谢@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 { }
            }
        }
    }


}

Sample use: 样品用途:

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

I've written a method that allows emty lines, outcommenting and quoting within the file. 我写了一个方法,允许在文件中使用emty行,取消注释和引用。

Examples: 例子:

var1="value1" VAR1 = “VALUE1”
var2='value2' VAR2 = '值'

'var3=outcommented “VAR3 = outcommented
;var4=outcommented, too ; var4 =也取消了

Here's the method: 这是方法:

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

Yet another answer (in January 2018) to the old question (in January 2009). 对旧问题(2009年1月)的另一个答案(2018年1月)。

The specification of Java properties file is described in the JavaDoc of java.util.Properties.load(java.io.Reader) . Java属性文件的规范在java.util.Properties.load(java.io.Reader)的JavaDoc中描述。 One problem is that the specification is a bit complicated than the first impression we may have. 一个问题是规范比我们可能有的第一印象有点复杂。 Another problem is that some answers here arbitrarily added extra specifications - for example, ; 另一个问题是,一些答案在这里任意添加额外的规格-例如, ; and ' are regarded as starters of comment lines but they should not be. 并且'被视为评论界的开端,但他们不应该。 Double/single quotations around property values are removed but they should not be. 属性值周围的双/单引号将被删除,但它们不应该被删除。

The following are points to be considered. 以下是要考虑的要点。

  1. There are two kinds of line, natural lines and logical lines . 有两种线, 自然线逻辑线
  2. A natural line is terminated by \\n , \\r , \\r\\n or the end of the stream. 自然行由\\n\\r\\r\\n或流的末尾终止。
  3. A logical line may be spread out across several adjacent natural lines by escaping the line terminator sequence with a backslash character \\ . 通过使用反斜杠字符\\转义行终止符序列,逻辑行可以分布在几个相邻的自然行中。
  4. Any white space at the start of the second and following natural lines in a logical line are discarded. 逻辑行中第二个和后续自然行开头的任何空格都将被丢弃。
  5. White spaces are space ( 白色空间是空间( , \ ), tab ( \\t , \ ) and form feed ( \\f , \ ). \ ),制表符( \\t\ )和换页符( \\f\ )。
  6. As stated explicitly in the specification, "it is not sufficient to only examine the character preceding a line terminator sequence to decide if the line terminator is escaped; there must be an odd number of contiguous backslashes for the line terminator to be escaped. Since the input is processed from left to right, a non-zero even number of 2n contiguous backslashes before a line terminator (or elsewhere) encodes n backslashes after escape processing." 正如在规范中明确指出的那样, “仅检查行终止符序列之前的字符以确定行终止符是否被转义是不够的;必须有奇数个连续的反斜杠才能对行终止符进行转义。输入从左到右处理,在行终止符(或其他地方)在转义处理后编码n个反斜杠之前,非偶数偶数个2n个连续反斜杠。
  7. = is used as the separator between a key and a value. =用作键和值之间的分隔符。
  8. : is used as the separator between a key and a value, too. :也用作键和值之间的分隔符。
  9. The separator between a key and a value can be omitted. 可以省略键和值之间的分隔符。
  10. A comment line has # or ! 注释行有#! as its first non-white space characters, meaning leading white spaces before # or ! 作为它的第一个非白色空格字符,意味着在#或之前引领空白区域! are allowed. 被允许。
  11. A comment line cannot be extended to next natural lines even its line terminator is preceded by \\ . 注释行不能扩展到下一个自然行,即使其行终止符前面有\\
  12. As stated explicitly in the specification, = , : and white spaces can be embedded in a key if they are escaped by backslashes. 正如在说明书中明确指出, =:和空格可嵌入的一个关键,如果他们用反斜杠转义。
  13. Even line terminator characters can be included using \\r and \\n escape sequences. 甚至可以使用\\r\\n转义序列包含行终止符。
  14. If a value is omitted, an empty string is used as a value. 如果省略值,则使用空字符串作为值。
  15. \\uxxxx is used to represent a Unicode character. \\uxxxx用于表示Unicode字符。
  16. A backslash character before a non-valid escape character is not treated as an error; 非有效转义字符前的反斜杠字符不会被视为错误; it is silently dropped. 它是默默地丢弃的。

So, for example, if test.properties has the following content: 因此,例如,如果test.properties具有以下内容:

# 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

it should be interpreted as the following key-value pairs. 它应该被解释为以下键值对。

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

PropertiesLoader class in Authlete.Authlete NuGet package can interpret the format of the specification. Authlete.Authlete NuGet包中的PropertiesLoader类可以解释规范的格式。 The example code below: 以下示例代码:

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

will generate this output: 将生成此输出:

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

An equivalent example in Java is as follows: Java中的等效示例如下:

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

The source code, PropertiesLoader.cs , can be found in authlete-csharp . 源代码PropertiesLoader.cs可以在authlete-csharp中找到。 xUnit tests for PropertiesLoader are written in PropertiesLoaderTest.cs . 的xUnit的测试PropertiesLoader都写在PropertiesLoaderTest.cs

Yeah there's no built in classes to do this that I'm aware of. 是的,我知道没有内置的课程可以做到这一点。

But that shouldn't really be an issue should it? 但那不应该是一个问题吗? It looks easy enough to parse just by storing the result of Stream.ReadToEnd() in a string, splitting based on new lines and then splitting each record on the = character. 通过将Stream.ReadToEnd()的结果存储在字符串中,基于新行拆分然后拆分=字符上的每条记录,看起来很容易解析。 What you'd be left with is a bunch of key value pairs which you can easily toss into a dictionary. 你剩下的就是一堆键值对,你可以很容易地把它们扔进字典里。

Here's an example that might work for you: 这是一个可能适合您的示例:

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

Here's an example of how to use it: 以下是如何使用它的示例:

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

The real answer is no (at least not by itself). 真正的答案是否定的(至少不是单独的)。 You can still write your own code to do it. 您仍然可以编写自己的代码来执行此操作。

C# generally uses xml-based config files rather than the *.ini-style file like you said, so there's nothing built-in to handle this. C#通常使用基于xml的配置文件而不是像你所说的* .ini风格的文件,因此没有内置的处理它。 However, google returns a number of promising results . 然而,谷歌返回了一些有希望的结果

I don't know of any built-in way to do this. 我不知道有任何内置的方法来做到这一点。 However, it would seem easy enough to do, since the only delimiters you have to worry about are the newline character and the equals sign. 但是,这似乎很容易做到,因为你必须担心的唯一分隔符是换行符和等号。

It would be very easy to write a routine that will return a NameValueCollection, or an IDictionary given the contents of the file. 编写一个返回NameValueCollection的例程或给定文件内容的IDictionary非常容易。

There are several NuGet packages for this, but all are currently in pre-release version. 有几个NuGet包,但目前都处于预发布版本。

[Update] As of June 2018, Capgemini.Cauldron.Core.JavaProperties is now in a stable version (version 2.1.0 and 3.0.20). [更新]截至2018年6月, Capgemini.Cauldron.Core.JavaProperties现在处于稳定版本(版本2.1.0和3.0.20)。

You can also use C# automatic property syntax with default values and a restrictive set. 您还可以将C#自动属性语法与默认值和限制集一起使用。 The advantage here is that you can then have any kind of data type in your properties "file" (now actually a class). 这里的优点是,您可以在属性“文件”中拥有任何类型的数据类型(现在实际上是一个类)。 The other advantage is that you can use C# property syntax to invoke the properties. 另一个优点是您可以使用C#属性语法来调用属性。 However, you just need a couple of lines for each property (one in the property declaration and one in the constructor) to make this work. 但是,您只需要为每个属性添加几行(一个在属性声明中,一个在构造函数中)以使其工作。

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

I realize that this isn't exactly what you're asking, but just in case: 我意识到这不是你所要求的,但以防万一:

When you want to load an actual Java properties file, you'll need to accomodate its encoding. 如果要加载实际的 Java属性文件,则需要适应其编码。 The Java docs indicate that the encoding is ISO 8859-1, which contains some escape sequences that you might not correctly interpret. Java文档表明编码是ISO 8859-1,其中包含一些您可能无法正确解释的转义序列。 For instance look at this SO answer to see what's necessary to turn UTF-8 into ISO 8859-1 (and vice versa) 例如,看看这个SO答案 ,看看将UTF-8变成ISO 8859-1的必要条件(反之亦然)

When we needed to do this, we found an open-source PropertyFile.cs and made a few changes to support the escape sequences. 当我们需要这样做时,我们找到了一个开源的PropertyFile.cs并进行了一些更改以支持转义序列。 This class is a good one for read/write scenarios. 这个类对于读/写场景来说是一个很好的类。 You'll need the supporting PropertyFileIterator.cs class as well. 您还需要支持的PropertyFileIterator.cs类。

Even if you're not loading true Java properties, make sure that your prop file can express all the characters you need to save (UTF-8 at least) 即使您没有加载真正的Java属性,也要确保您的prop文件可以表达您需要保存的所有字符(至少UTF-8)

There is the exact solution of what you want. 有你想要的确切解决方案。 please find the article from here 请从这里找到文章

his code has a bunch of strong points regarding efficiency. 他的代码在效率方面有很多优点。

  1. The application does not load the text file in every request. 应用程序不会在每个请求中加载文本文件。 It loads the text file only once to the memory. 它只将文本文件加载到内存中一次。 For the subsequent request, it returns the value directly from the memory. 对于后续请求,它直接从内存返回值。 This is much more efficient if your text file contains thousands or more key-value pairs. 如果您的文本文件包含数千或更多键值对,则效率会更高。
  2. Any change in the text file does not require application restart. 文本文件中的任何更改都不需要重新启动应用程序。 A file system watcher has been used to keep track of the file state. 文件系统观察器已用于跟踪文件状态。 If it changes, it triggers an event and loads the new changes accordingly to memory so that, you can change the text file in one application/text editor and see the changed effect in the web application. 如果它发生更改,它会触发事件并相应地将新更改加载到内存中,以便您可以在一个应用程序/文本编辑器中更改文本文件,并在Web应用程序中查看更改的效果。
  3. You are not only able to use it in a web application but also able to use it in any desktop application. 您不仅可以在Web应用程序中使用它,还可以在任何桌面应用程序中使用它。

Thanks. 谢谢。 Have a nice day. 祝你今天愉快。

No there is not : But I have created one easy class to help : 不,没有:但我创建了一个简单的课程来帮助:

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

    }
}

Hope this helps. 希望这可以帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM