.NET加载和解析与Java属性类等效的属性文件吗?
-
20-08-2019 - |
题
C#中是否有一种简单的方法可以读取一个属性文件,该文件将每个属性都在单独的行上,然后是等于符号和值,例如以下内容:
ServerName=prod-srv1
Port=8888
CustomProperty=Any value
在Java中,属性类可以轻松处理这一点:
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"));
我可以轻松地将文件加载到c#中并分析每行,但是是否内置的方式可以轻松获取属性而无需解析关键名称并自己等于签名?我发现的C#信息似乎总是偏爱XML,但这是我无法控制的现有文件,我希望以现有格式保持其状态,因为它需要更多时间让另一个团队将其更改为XML而不是解析现有文件。
解决方案
没有对此没有内置的支持。
您必须自己制作自己的“ inifilereader”。也许是这样的?
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"]);
编辑:更新以反映保罗的评论。
其他提示
大多数Java“ .properties”文件可以通过假设“ =”是分隔符来拆分 - 但是格式比该文件要复杂得多,并且允许嵌入空格,平等,newlines和属性名称或值中的任何Unicode字符。
我需要为C#应用程序加载一些Java属性,因此我已经实现了Javaproperties.cs以使用与Java版本相同的方法正确读写和写入“ .properties”格式化文件 - 您可以在 http://www.kajabity.com/index.php/2009/06/loading-java-properties-files-files-in-csharp/.
在那里,您会找到一个包含类的C#源的zip文件以及我对其进行测试的一些示例属性文件。
享受!
最后一堂课。谢谢 @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 { }
}
}
}
}
样品使用:
//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()
我已经写了一种方法,该方法允许在文件中进行Emty线,量变得越野和引用。
例子:
var1 =“ value1”
var2 ='value2'
'var3 =量
; var4 =也已经淘汰
这是方法:
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;
}
(2018年1月)对旧问题(2009年1月)还有另一个答案。
Java属性文件的规范在Javadoc中描述 java.util.properties.load(Java.io.Reader)
. 。一个问题是,规格比我们可能的第一印象要复杂。另一个问题是这里有一些答案任意添加了额外的规格 - 例如 ;
和 '
被视为评论线的首发者,但不应该是。围绕属性值的双/单引号被删除,但不应该是。
以下是要考虑的要点。
- 有两种行, 天然线 和 逻辑线.
- 自然线被终止
\n
,\r
,\r\n
或流的末端。 - 逻辑线可以通过以后斜切字符逃脱线终结器序列来散布在几条相邻的自然线上
\
. - 第二次开始时的任何空白和逻辑线中的自然线都被丢弃。
- 白色空间是空间(
,
\u0020
), 标签 (\t
,\u0009
)并形成饲料(\f
,\u000C
). - 如规范中明确说明的 “仅检查线路终止序列前的字符以决定是否逃脱了线路是不够的;必须有一个奇数的连续后斜线才能逃脱。 ,在线路终止器(或其他地方)之前的2N连续后斜线的非零数量均匀编码n后斜线。”
=
用作键和值之间的分离器。:
也用作键和值之间的分离器。- 可以省略键和值之间的分离器。
- 评论行有
#
或者!
作为其第一个非白色空间字符,意味着前面的白色空间#
或者!
被允许。 - 即使在其线路终止器之前,评论行也不能扩展到下一个自然线
\
. - 如规范中明确说明的
=
,:
如果白色空间被反斜线逃脱,则可以将它们嵌入钥匙中。 - 甚至可以使用线终结者字符
\r
和\n
逃脱序列。 - 如果省略了一个值,则将一个空字符串用作值。
\uxxxx
用于表示Unicode字符。- 在非浮游逃脱字符之前的后斜切角色不被视为错误。它被默默掉落。
因此,例如,如果 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
它应解释为以下键值对。
+------+--------------------+
| KEY | VALUE |
+------+--------------------+
| key1 | value1 |
| key2 | value2 |
| key3 | value3 |
| key4 | value4 |
| key5 | value5 |
| key6 | value6 |
| : = | \colon\space\equal |
+------+--------------------+
PropertiesLoader
上课 authlete.authlete Nuget软件包可以解释规范的格式。下面的示例代码:
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}");
}
}
}
}
将生成此输出:
key1 = value1
key2 = value2
key3 = value3
key4 = value4
key5 = value5
key6 = value6
: = = \colon\space\equal
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());
}
}
}
源代码, propertiesLoader.cs
, ,可以在 authlete-charp. Xunit 测试 PropertiesLoader
写在里面 propertiesloadertest.cs
.
是的,我知道没有内置的课堂可以做到这一点。
但这真的不应该是一个问题吗?仅通过存储的结果来解析看起来很容易 Stream.ReadToEnd()
在字符串中,基于新行分开,然后将每个记录拆分 =
特点。剩下的是一堆钥匙值对,您可以轻松地将其扔进字典中。
这是一个可能对您有用的示例:
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;
}
这是如何使用它的示例:
Dictionary<string,string> Properties = GetProperties("data.txt");
Console.WriteLine("Hello: " + Properties["Hello"]);
Console.ReadKey();
真正的答案是否(至少不是本身)。您仍然可以编写自己的代码来执行此操作。
C#通常使用基于XML的配置文件,而不是像您所说的那样 *INI式文件,因此没有内置的内容可以处理。但是,Google返回 有希望的结果数量.
我不知道有任何内在方法可以做到这一点。但是,这似乎很容易做到,因为您唯一需要担心的分界符是newline字符和平等符号。
编写将返回名称valuecollection或给定文件内容的idictionary的例程非常容易。
您还可以使用具有默认值和限制性集的C#自动属性语法。这里的优点是,您可以在“文件”属性中拥有任何类型的数据类型(现在实际上是类)。另一个优点是您可以使用C#属性语法来调用属性。但是,您只需要为每个属性(属性声明中的一个,一个在构造函数中)进行几行即可完成此工作。
using System;
namespace ReportTester {
class TestProperties
{
internal String ReportServerUrl { get; private set; }
internal TestProperties()
{
ReportServerUrl = "http://myhost/ReportServer/ReportExecution2005.asmx?wsdl";
}
}
}
为此有几个Nuget软件包,但当前都在预发行版中。
- capgemini.cauldron.core.javaproperties 2.0.39-beta
- kajabity.tools.java 0.2.6638.28124
更新]截至2018年6月, capgemini.cauldron.core.javaproperties 现在以稳定版本(版本2.1.0和3.0.20)为单位。
我意识到这不是您要问的,而是以防万一:
当您想加载一个 实际的 Java属性文件,您需要适应其编码。 Java文档 表明编码是ISO 8859-1,其中包含一些您可能无法正确解释的逃生序列。例如看 这个答案 要查看将UTF-8变成ISO 8859-1的必要条件(反之亦然)
当我们需要这样做时,我们找到了一个开源 propertyfile.cs 并进行了一些更改以支持逃生序列。该课程是阅读/写作场景的好课程。您需要支持 propertyFileiterator.cs 也是课。
即使您没有加载真正的Java属性,请确保您的道具文件可以表达您需要保存的所有字符(至少UTF-8)
您想要的是确切的解决方案。请从 这里
他的代码在效率方面有很多强调。
- 该应用程序不会将文本文件加载到每个请求中。它仅将文本文件加载到内存一次。对于后续请求,它直接从内存返回值。如果您的文本文件包含数千个或更多的键值对,这将更加有效。
- 文本文件中的任何更改都不需要重新启动应用程序。文件系统观察器已用于跟踪文件状态。如果更改,它会触发事件并将新更改加载到内存中,以便您可以在一个应用程序/文本编辑器中更改文本文件,并在Web应用程序中查看更改的效果。
- 您不仅能够在Web应用程序中使用它,还可以在任何桌面应用程序中使用它。
谢谢。祝你今天过得愉快。
没有:但是我创建了一个简单的课程来帮助:
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");
}
}
}
希望这可以帮助。