web-dev-qa-db-ja.com

.NETは、Java Propertiesクラスと同等のプロパティファイルをロードおよび解析できますか?

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に変更するために別のチームを取得するのに時間がかかるため、既存の形式のままにしておきます既存のファイルを解析するよりも。

53
Tai Squared

いいえ、これに対する組み込みのサポートはありません。

独自の「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"]);

編集:ポールのコメントを反映するために更新されました。

40
Jesper Palm

ほとんどのJava ".properties"ファイルは、 "="をセパレータと想定して分割できます-ただし、形式はそれよりもかなり複雑で、スペース、等号、改行、Unicodeを埋め込むことができますプロパティ名または値のいずれかの文字。

C#アプリケーションのいくつかのJavaプロパティをロードする必要があったため、JavaProperties.csを実装して、Javaバージョン- http://www.kajabity.com/index.php/2009/06/loading-Java-properties-files-in-csharp/ で見つけることができます。

そこには、クラスのC#ソースと、テストしたサンプルプロパティファイルを含むZipファイルがあります。

楽しい!

18
Kajabity

最終クラス。ありがとう @ 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()
16
Nick Rimmer

私は、ファイル内で空行、コメントアウト、および引用を許可するメソッドを作成しました。

例:

var1 = "value1"
var2 = 'value2'

'var3 = outcommented
; 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;
}
7
eXXL

古い質問(2009年1月)に対する別の回答(2018年1月)。

Javaプロパティファイルの仕様はJava.util.Properties.load(Java.io.Reader)のJavaDocで説明されています。1つの問題は、仕様が最初の印象より少し複雑であるということです。ここでのいくつかの答えは、追加の仕様を任意に追加しました-たとえば、;'はコメント行の開始点と見なされますが、そうすべきではありません。 。

考慮すべき点は次のとおりです。

  1. 行には、自然な行論理的な行の2種類があります。
  2. 自然な行は、\n\r\r\n、またはストリームの終わりで終了します。
  3. 論理行は、バックスラッシュ文字\を使用して行終了記号シーケンスをエスケープすることにより、複数の隣接する自然行にまたがって配置できます。
  4. 論理行の2行目以降の自然行の先頭にある空白はすべて破棄されます。
  5. 空白は、スペース(、\u0020)、タブ(\t\u0009)およびフォームフィード(\f\u000C)です。
  6. 仕様で明示的に述べられているように、」は、行末記号がエスケープされているかどうかを判断するために、行末記号シーケンスの前の文字を調べるだけでは十分ではありません。入力は左から右に処理されるので、行ターミネータ(または他の場所)の前のゼロ以外の偶数の2n連続するバックスラッシュは、エスケープ処理後にn個のバックスラッシュをエンコードします。 "
  7. =は、キーと値の間の区切り文字として使用されます。
  8. :は、キーと値の間の区切り文字としても使用されます。
  9. キーと値の間の区切り文字は省略できます。
  10. コメント行には、最初の非空白文字として#または!があります。つまり、#または!が許可される前の先頭の空白を意味します。
  11. コメント行は、その行末記号の前に\があっても、次の自然行に拡張できません。
  12. 仕様で明示的に述べられているように、バックスラッシュによってエスケープされる場合、=:および空白をキーに埋め込むことができます。
  13. \rおよび\nエスケープシーケンスを使用して、行終端文字も含めることができます。
  14. 値を省略すると、空の文字列が値として使用されます。
  15. \uxxxxは、Unicode文字を表すために使用されます。
  16. 無効なエスケープ文字の前のバックスラッシュ文字はエラーとして扱われません。静かにドロップされます。

そのため、たとえば、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 |
+------+--------------------+

Authlete.Authlete NuGetパッケージのPropertiesLoaderクラスは、仕様の形式を解釈できます。以下のサンプルコード:

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-csharp にあります。 xUnitPropertiesLoaderのテストはPropertiesLoaderTest.csで記述されています。

5

うん、これを行うための組み込みのクラスはありません。

しかし、それは本当に問題になるべきではありませんか? 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();
2
Spencer Ruport

本当の答えは、(少なくとも、それ自体で)何もありません。あなたはまだそれを行うには、独自のコードを書くことができます。

2
Carl Thronson

C#は通常、前述の* .iniスタイルのファイルではなく、xmlベースの構成ファイルを使用するため、これを処理するための組み込み機能はありません。ただし、googleは 有望な結果の数 を返します。

1
Joel Coehoorn

これを行うための組み込みの方法は知りません。ただし、心配する必要があるのは改行文字と等号のみであるため、簡単に実行できるように思えます。

NameValueCollectionを返すルーチン、またはファイルの内容を指定したIDictionaryを作成するのは非常に簡単です。

1
casperOne

また、C#の自動プロパティ構文を使用して、デフォルト値と制限セットを使用することもできます。ここでの利点は、プロパティ "ファイル"(実際にはクラス)に任意の種類のデータ型を含めることができることです。もう1つの利点は、C#プロパティ構文を使用してプロパティを呼び出すことができることです。ただし、これを機能させるには、プロパティごとに数行(プロパティ宣言に1行とコンストラクタに1行)が必要です。

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

これにはいくつかのNuGetパッケージがありますが、現在はすべてプレリリースバージョンです。

[更新] 2018年6月現在、 Capgemini.Cauldron.Core.JavaProperties は安定バージョン(バージョン2.1.0および3.0.20)になっています。

1
Mike Rosoft

ありません:しかし、私は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");
        }

    }
}

お役に立てれば。

0
ApGokani

これはまさにあなたが求めているものではなく、念のためです:

actualJavaプロパティファイルをロードする場合、そのエンコーディングに対応する必要があります。 Java docs は、エンコードがISO 8859-1であり、正しく解釈できないエスケープシーケンスが含まれていることを示します。たとえば、 this SO answer UTF-8をISO 8859-1に変換するために必要なものを確認するには(およびその逆)

これを行う必要があるとき、オープンソース PropertyFile.cs を見つけ、エスケープシーケンスをサポートするためにいくつかの変更を行いました。このクラスは、読み取り/書き込みシナリオに適しています。サポートする PropertyFileIterator.cs クラスも必要になります。

True Javaプロパティをロードしていない場合でも、propファイルが保存する必要のあるすべての文字を表現できることを確認してください(少なくともUTF-8)

0
Steve Eisner

あなたが望むものの正確な解決策があります。 こちら から記事を見つけてください

彼のコードには、効率に関する多くの長所があります。

  1. アプリケーションは、すべてのリクエストでテキストファイルをロードするわけではありません。テキストファイルを一度だけメモリにロードします。後続のリクエストでは、メモリから直接値を返します。テキストファイルに数千以上のキーと値のペアが含まれている場合、これははるかに効率的です。
  2. テキストファイルを変更しても、アプリケーションを再起動する必要はありません。ファイルシステムウォッチャーは、ファイルの状態を追跡するために使用されています。変更された場合、イベントをトリガーし、それに応じて新しい変更をメモリにロードします。1つのアプリケーション/テキストエディターでテキストファイルを変更し、Webアプリケーションで変更された効果を確認できます。
  3. Webアプリケーションで使用できるだけでなく、デスクトップアプリケーションでも使用できます。

ありがとう。良い一日を。

0
arefinsami