.NET は Java Properties クラスと同等のプロパティ ファイルをロードして解析できますか?
-
20-08-2019 - |
質問
C# で、次のような、各プロパティの後に等号と値が続く個別の行にあるプロパティ ファイルを読み取る簡単な方法はありますか。
ServerName=prod-srv1
Port=8888
CustomProperty=Any value
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"));
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」ファイルは、「=」が区切り文字であると想定して分割できますが、形式はそれよりもはるかに複雑で、スペース、等号、改行、および任意の Unicode 文字をプロパティ名または値に埋め込むことができます。
C# アプリケーションにいくつかの Java プロパティをロードする必要があったので、Java バージョンと同じアプローチを使用して「.properties」形式のファイルを正しく読み書きできるように JavaProperties.cs を実装しました。これは次の場所にあります。 http://www.kajabity.com/index.php/2009/06/loading-java-properties-files-in-csharp/.
そこには、クラスの C# ソースと、それをテストしたいくつかのサンプル プロパティ ファイルを含む zip ファイルがあります。
楽しむ!
finalクラス。おかげ @ 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()
私は、ファイル内outcommentingと引用、emtyラインを可能にする方法を書いてます。
例:
VAR1 = "VALUE1"
var2のは= 'value2の'
'VAR3 = outcommented
; VAR4 = outcommented、あまりに
ここでの方法です。
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;
}
古い質問 (2009 年 1 月) に対するさらに別の回答 (2018 年 1 月)。
Java プロパティ ファイルの仕様は、JavaDoc に記載されています。 java.util.Properties.load(java.io.Reader)
. 。問題の 1 つは、仕様が第一印象よりも少し複雑であることです。もう1つの問題は、ここでの一部の回答が追加の仕様を恣意的に追加していることです。たとえば、 ;
そして '
はコメント行の開始とみなされますが、そうすべきではありません。プロパティ値を囲む二重引用符または一重引用符は削除されますが、削除すべきではありません。
考慮すべき点は以下のとおりです。
- ラインは2種類ありますが、 自然なライン そして 論理行.
- 自然なラインは次のように終了します。
\n
,\r
,\r\n
またはストリームの終わり。 - バックスラッシュ文字で行終了シーケンスをエスケープすることにより、論理行を複数の隣接する自然な行にまたがって広げることができます。
\
. - 論理行の 2 番目以降の自然な行の先頭にある空白は破棄されます。
- 空白はスペースです(
,
\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());
}
}
}
ソースコードは、 プロパティローダー.cs
, 、で見つけることができます authlete-csharp. xユニット のテスト 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#が、一般的ではなく*の.ini形式のファイルよりも、XMLベースの設定ファイルを使用していますので、これを処理するために、内蔵のものは何もありません。しかし、Googleが有望な結果するの数を返します。
これを行うための組み込みの方法がわかりません。ただし、気にする必要がある区切り文字は改行文字と等号だけであるため、これは十分簡単に思えるかもしれません。
ファイルの内容を指定して、NameValueCollection または IDictionary を返すルーチンを作成するのは非常に簡単です。
また、デフォルト値であり、限定セットを使用してC#の自動プロパティの構文を使用することができます。ここでの利点は、あなたがあなたの特性「ファイル」(今、実際にクラス)でのデータ型のいずれかの種類を持つことができるということです。他の利点は、あなたがプロパティを呼び出すためにC#プロパティの構文を使用することができるということです。しかし、あなたはちょうどこの作品を作るために各プロパティの数行(プロパティ宣言し、コンストラクタ内の1つの内の1つ)が必要です。
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 ベータ版
- Kajabity.ツール.Java 0.2.6638.28124
更新] 2018年6月現在、 Capgemini.Cauldron.Core.JavaProperties 現在は安定バージョン (バージョン 2.1.0 および 3.0.20) です。
私は、これはあなたが求めている正確に何ではありませんが、念のことを実現します
は、の実際ののJavaプロパティを使用すると、そのエンコーディングを収容する必要があります、ファイルをロードする場合。ことを示しているののJavaドキュメントエンコードは、あなたが正しく解釈されない場合がありますいくつかのエスケープシーケンスが含まれているISO 8859-1、です。これはSOだものを見るためにに答えるhref="https://stackoverflow.com/questions/1273986/converting-utf-8-to-iso-8859-1-in-java">例えば
私たちはこれを行うために必要な場合には、我々はオープンソースの PropertyFile.cs とエスケープシーケンスをサポートするためにいくつかの変更を加えました。このクラスは、読み取り/書き込みシナリオの良いものです。あなたにもサポート PropertyFileIterator.cs のクラスが必要になります。 あなたは真のJavaプロパティをロードしていない場合でも、あなたの小道具のファイルには、(少なくともUTF-8)を保存するために必要なすべての文字を表現できることを確認してください。
あなたが望むものに対する正確な解決策があります。から記事を見つけてください ここ
彼のコードには効率に関して多くの優れた点があります。
- アプリケーションは、リクエストごとにテキスト ファイルをロードするわけではありません。メモリにテキストファイルを1回だけロードします。後続の要求のために、それはメモリから値を直接返します。これは、テキストファイルに数千以上のキー価値ペアが含まれている場合、はるかに効率的です。
- テキスト ファイルを変更しても、アプリケーションを再起動する必要はありません。ファイルウォッチャーは、ファイル状態を追跡するために使用されています。変更された場合、イベントをトリガーし、新しい変更をメモリにロードして、1つのアプリケーション/テキストエディターのテキストファイルを変更して、Webアプリケーションで変更された効果を確認できます。
- Webアプリケーションで使用できるだけでなく、任意のデスクトップアプリケーションで使用することもできます。
ありがとう。良い1日を。
はありませんありません。しかし、私は助けるために1つの簡単なクラスを作成しています:
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");
}
}
}
この情報がお役に立てば幸いです。