簡體   English   中英

.NET可以加載和解析與Java Properties類等效的屬性文件嗎?

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

在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版本相同的方法實現了JavaProperties.cs以正確讀取和寫入“.properties”格式化文件 - 您可以在http://www.kajabity找到它.com / index.php / 2009/06 / loading-java-properties-files-in-csharp /

在那里,你會找到一個zip文件,其中包含該類的C#源代碼以及我測試過的一些示例屬性文件。

請享用!

最后一堂課。 謝謝@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 = '值'

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

對舊問題(2009年1月)的另一個答案(2018年1月)。

Java屬性文件的規范在java.util.Properties.load(java.io.Reader)的JavaDoc中描述。 一個問題是規范比我們可能有的第一印象有點復雜。 另一個問題是,一些答案在這里任意添加額外的規格-例如, ; 並且'被視為評論界的開端,但他們不應該。 屬性值周圍的雙/單引號將被刪除,但它們不應該被刪除。

以下是要考慮的要點。

  1. 有兩種線, 自然線邏輯線
  2. 自然行由\\n\\r\\r\\n或流的末尾終止。
  3. 通過使用反斜杠字符\\轉義行終止符序列,邏輯行可以分布在幾個相鄰的自然行中。
  4. 邏輯行中第二個和后續自然行開頭的任何空格都將被丟棄。
  5. 白色空間是空間( \ ),制表符( \\t\ )和換頁符( \\f\ )。
  6. 正如在規范中明確指出的那樣, “僅檢查行終止符序列之前的字符以確定行終止符是否被轉義是不夠的;必須有奇數個連續的反斜杠才能對行終止符進行轉義。輸入從左到右處理,在行終止符(或其他地方)在轉義處理后編碼n個反斜杠之前,非偶數偶數個2n個連續反斜杠。
  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中找到。 的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風格的文件,因此沒有內置的處理它。 然而,谷歌返回了一些有希望的結果

我不知道有任何內置的方法來做到這一點。 但是,這似乎很容易做到,因為你必須擔心的唯一分隔符是換行符和等號。

編寫一個返回NameValueCollection的例程或給定文件內容的IDictionary非常容易。

有幾個NuGet包,但目前都處於預發布版本。

[更新]截至2018年6月, Capgemini.Cauldron.Core.JavaProperties現在處於穩定版本(版本2.1.0和3.0.20)。

您還可以將C#自動屬性語法與默認值和限制集一起使用。 這里的優點是,您可以在屬性“文件”中擁有任何類型的數據類型(現在實際上是一個類)。 另一個優點是您可以使用C#屬性語法來調用屬性。 但是,您只需要為每個屬性添加幾行(一個在屬性聲明中,一個在構造函數中)以使其工作。

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

我意識到這不是你所要求的,但以防萬一:

如果要加載實際的 Java屬性文件,則需要適應其編碼。 Java文檔表明編碼是ISO 8859-1,其中包含一些您可能無法正確解釋的轉義序列。 例如,看看這個SO答案 ,看看將UTF-8變成ISO 8859-1的必要條件(反之亦然)

當我們需要這樣做時,我們找到了一個開源的PropertyFile.cs並進行了一些更改以支持轉義序列。 這個類對於讀/寫場景來說是一個很好的類。 您還需要支持的PropertyFileIterator.cs類。

即使您沒有加載真正的Java屬性,也要確保您的prop文件可以表達您需要保存的所有字符(至少UTF-8)

有你想要的確切解決方案。 請從這里找到文章

他的代碼在效率方面有很多優點。

  1. 應用程序不會在每個請求中加載文本文件。 它只將文本文件加載到內存中一次。 對於后續請求,它直接從內存返回值。 如果您的文本文件包含數千或更多鍵值對,則效率會更高。
  2. 文本文件中的任何更改都不需要重新啟動應用程序。 文件系統觀察器已用於跟蹤文件狀態。 如果它發生更改,它會觸發事件並相應地將新更改加載到內存中,以便您可以在一個應用程序/文本編輯器中更改文本文件,並在Web應用程序中查看更改的效果。
  3. 您不僅可以在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");
        }

    }
}

希望這可以幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM