Development Tip

.NET은 Java Properties 클래스에 해당하는 속성 파일을로드하고 구문 분석 할 수 있습니까?

yourdevel 2021. 1. 7. 20:04
반응형

.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로 변경하는 데 더 많은 시간이 필요하므로 기존 형식으로 유지하는 것이 좋습니다. 기존 파일을 구문 분석하는 것보다.


이에 대한 기본 제공 지원이 없습니다.

자신 만의 "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"]);

편집 : Paul의 의견을 반영하도록 업데이트되었습니다.


대부분의 Java ".properties"파일은 "="가 구분 자라고 가정하여 분할 할 수 있습니다. 그러나 형식은 그보다 훨씬 더 복잡하며 속성 이름이나 값에 공백, 같음, 줄 바꿈 및 유니 코드 문자를 포함 할 수 있습니다.

Java 버전과 동일한 접근 방식을 사용하여 ".properties"형식의 파일을 올바르게 읽고 쓰기 위해 JavaProperties.cs를 구현 했으므로 C # 응용 프로그램에 대한 일부 Java 속성을로드해야했습니다. http : //www.kajabity 에서 찾을 수 있습니다 . .com / index.php / 2009 / 06 / loading-java-properties-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 줄, outcommenting 및 quoting을 허용하는 방법을 작성했습니다.

예 :

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. 라인, 두 가지 종류가 있습니다 자연 라인논리적 라인 .
  2. 천연 라인이 종료되는 \n, \r, \r\n스트림 또는 끝.
  3. 논리 줄은 백 슬래시 문자로 줄 종결 자 시퀀스를 이스케이프하여 인접한 여러 자연 줄에 걸쳐 분산 될 수 있습니다 \.
  4. 두 번째 시작 부분의 공백과 논리 줄의 다음 자연 줄은 모두 삭제됩니다.
  5. 공백은 공백 ( , \u0020), 탭 ( \t, \u0009) 및 용지 공급 ( \f, \u000C)입니다.
  6. 사양에서 명시 적으로 언급했듯이 "줄 종결자가 이스케이프되는지 여부를 결정하기 위해 줄 종결 자 시퀀스 앞의 문자를 검사하는 것만으로는 충분하지 않습니다. 줄 종결자를 이스케이프하려면 연속 된 백 슬래시 수가 홀수 여야합니다. 입력은 왼쪽에서 오른쪽으로 처리되며, 줄 종결 자 (또는 다른 위치) 앞의 2n 연속 백 슬래시의 0이 아닌 짝수는 이스케이프 처리 후 n 개의 백 슬래시를 인코딩합니다. "
  7. = 키와 값 사이의 구분 기호로 사용됩니다.
  8. : 키와 값 사이의 구분 기호로도 사용됩니다.
  9. 키와 값 사이의 구분 기호는 생략 할 수 있습니다.
  10. 주석 행에는 #또는 !첫 번째 공백이 아닌 문자가 있습니다. 즉, #또는 앞의 공백 !이 허용됩니다.
  11. 주석 줄은 줄 종결 자 앞에가 있더라도 다음 자연 줄로 확장 할 수 없습니다 \.
  12. 사양에서 명시 적으로 언급했듯이 =, :공백은 백 슬래시로 이스케이프되는 경우 키에 포함될 수 있습니다.
  13. 줄 종결 문자도 \r\n이스케이프 시퀀스를 사용하여 포함될 수 있습니다 .
  14. 값이 생략되면 빈 문자열이 값으로 사용됩니다.
  15. \uxxxx 유니 코드 문자를 나타내는 데 사용됩니다.
  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 |
+------+--------------------+

PropertiesLoaderAuthlete.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.csauthlete-csharp 에서 찾을 수 있습니다 . xUnit 테스트 PropertiesLoaderPropertiesLoaderTest.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;
}

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. 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.


You can also use C# automatic property syntax with default values and a restrictive set. 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. 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";
        }
   }
}

There are several NuGet packages for this, but all are currently in pre-release version.

[Update] As of June 2018, Capgemini.Cauldron.Core.JavaProperties is now in a stable version (version 2.1.0 and 3.0.20).


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. The Java docs indicate that the encoding is ISO 8859-1, which contains some escape sequences that you might not correctly interpret. For instance look at this SO answer to see what's necessary to turn UTF-8 into ISO 8859-1 (and vice versa)

When we needed to do this, we found an open-source PropertyFile.cs and made a few changes to support the escape sequences. This class is a good one for read/write scenarios. You'll need the supporting PropertyFileIterator.cs class as well.

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)


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.
  3. You are not only able to use it in a web application but also able to use it in any desktop application.

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.

ReferenceURL : https://stackoverflow.com/questions/485659/can-net-load-and-parse-a-properties-file-equivalent-to-java-properties-class

반응형