سؤال

هل هناك طريقة سهلة في C# لقراءة ملف خصائص يحتوي على كل خاصية على سطر منفصل متبوعًا بعلامة متساوية والقيمة ، مثل ما يلي:

ServerName=prod-srv1
Port=8888
CustomProperty=Any value

في جافا ، يتعامل فئة الخصائص مع هذا التحليل بسهولة:

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 في اسم أو قيمة الخاصية.

كنت بحاجة إلى تحميل بعض خصائص Java لتطبيق C# ، لذا قمت بتطبيق javaproperties.cs للقراءة والكتابة بشكل صحيح ". http://www.kajabity.com/index.php/2009/06/loading-java-properties-files-in-csharp/.

هناك ، ستجد ملفًا مضغوطًا يحتوي على مصدر 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 = '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) على السؤال القديم (في يناير 2009).

تم وصف مواصفات ملف خصائص Java في Javadoc of java.util.properties.load (java.io.reader). إحدى المشكلات هي أن المواصفات معقدة بعض الشيء من الانطباع الأول الذي قد لدينا. مشكلة أخرى هي أن بعض الإجابات هنا تمت إضافة مواصفات إضافية بشكل تعسفي - على سبيل المثال ، ; و ' تعتبر مبتدئين لخطوط التعليق ولكن لا ينبغي أن تكون كذلك. تتم إزالة الاقتباسات المزدوجة/الفردية حول قيم الممتلكات ولكن لا ينبغي أن تكون كذلك.

فيما يلي نقاط يجب مراعاتها.

  1. هناك نوعان من الخط ، الخطوط الطبيعية و خطوط منطقية.
  2. تم إنهاء الخط الطبيعي بواسطة \n, \r, \r\n أو نهاية الدفق.
  3. قد ينتشر خط منطقي عبر عدة خطوط طبيعية مجاورة عن طريق الهروب \.
  4. يتم التخلص من أي مساحة بيضاء في بداية الخطوط الطبيعية الثانية والمتابعة في خط منطقي.
  5. المساحات البيضاء مساحة (, \u0020)، التبويب (\t, \u0009) وتغذية الشكل (\f, \u000C).
  6. كما هو مذكور بشكل صريح في المواصفات ، "لا يكفي فحص الحرف الذي يسبق تسلسل طرفي خط ليقرر ما إذا كان المنهي الخط قد هرب ؛ يجب أن يكون هناك عدد فردي من الانزلاقات المتداخلة المتجاورة ليتم هروب المنهي الخط. نظرًا لأن المدخلات تتم معالجتها من اليسار إلى اليمين ، عدد غير صفري من 2N 2N المتجاورة المتجاورة قبل أن يشفر المنهي خط (أو في أي مكان آخر) n بعد معالجة الهروب. "
  7. = يستخدم كفاصل بين المفتاح والقيمة.
  8. : يستخدم كفاصل بين المفتاح والقيمة أيضًا.
  9. يمكن حذف الفاصل بين المفتاح والقيمة.
  10. خط التعليق لديه # أو ! كأول شخصيات فضاء غير بيضاء ، مما يعني أن المساحات البيضاء الرائدة من قبل # أو ! مسموح به.
  11. لا يمكن توسيع خط التعليق إلى الخطوط الطبيعية التالية حتى يسبقه المنهي الخط \.
  12. كما هو مذكور بشكل صريح في المواصفات ، =, : ويمكن تضمين المساحات البيضاء في مفتاح إذا هربت من قبل التراجع.
  13. يمكن تضمين أحرف Terminator حتى الخط \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 |
+------+--------------------+

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

مثال مكافئ في جافا هو كما يلي:

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-Style كما قلت ، لذلك لا يوجد شيء مدمج للتعامل مع هذا. ومع ذلك ، يعيد Google أ عدد النتائج الواعدة.

لا أعرف أي طريقة مدمجة للقيام بذلك. ومع ذلك ، يبدو من السهل القيام به ، لأن المحددات الوحيدة التي يجب أن تقلق بشأنها هي شخصية الخط الجديد وعلامة متساوية.

سيكون من السهل جدًا كتابة روتين سيعيد اسم NameValueCollection ، أو معرف بالنظر إلى محتويات الملف.

يمكنك أيضًا استخدام بناء جملة خاصية C# مع القيم الافتراضية ومجموعة تقييدية. الميزة هنا هي أنه يمكنك بعد ذلك الحصول على أي نوع من أنواع البيانات في "ملف" خصائصك (الآن في الواقع فئة). الميزة الأخرى هي أنه يمكنك استخدام بناء جملة خاصية C# لاستدعاء الخصائص. ومع ذلك ، فأنت بحاجة فقط إلى خطين لكل خاصية (واحد في إعلان الممتلكات وواحد في المنشئ) لجعل هذا العمل.

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

هناك العديد من حزم nuget لهذا ، ولكن جميعها موجودة حاليًا في إصدار ما قبل الإصدار.

تحديث] اعتبارًا من يونيو 2018 ، capgemini.cauldron.core.javaproperties هو الآن في إصدار مستقر (الإصدار 2.1.0 و 3.0.20).

أدرك أن هذا ليس بالضبط ما تطلبه ، ولكن فقط في حالة:

عندما تريد تحميل فِعلي ملف خصائص Java ، ستحتاج إلى استيعاب ترميزه. مستندات جافا تشير إلى أن الترميز هو ISO 8859-1 ، والذي يحتوي على بعض تسلسل الهروب الذي قد لا تفسره بشكل صحيح. على سبيل المثال انظر إلى هذا حتى الإجابة لمعرفة ما هو ضروري لتحويل UTF-8 إلى ISO 8859-1 (والعكس صحيح)

عندما نحتاج إلى القيام بذلك ، وجدنا مصدرًا مفتوحًا propertyfile.cs وقام ببعض التغييرات لدعم تسلسل الهروب. هذا الفصل جيد لسيناريوهات القراءة/الكتابة. ستحتاج إلى الدعم PropertyFileiterator.cs الطبقة كذلك.

حتى إذا لم تكن تقوم بتحميل خصائص Java الحقيقية ، فتأكد من أن ملف الدعامة الخاص بك يمكنه التعبير عن جميع الأحرف التي تحتاج إلى حفظها (UTF-8 على الأقل)

هناك الحل الدقيق لما تريده. الرجاء العثور على المقال من هنا

رمزه لديه مجموعة من النقاط القوية فيما يتعلق بالكفاءة.

  1. لا يقوم التطبيق بتحميل الملف النصي في كل طلب. يقوم بتحميل الملف النصي مرة واحدة فقط على الذاكرة. للطلب اللاحق ، يعيد القيمة مباشرة من الذاكرة. هذا أكثر كفاءة إذا كان ملفك النصي يحتوي على آلاف أو أكثر من أزواج القيمة الرئيسية.
  2. لا يتطلب أي تغيير في الملف النصي إعادة تشغيل التطبيق. تم استخدام مراقب نظام الملفات لتتبع حالة الملف. إذا تغير ، فإنه يؤدي إلى حدوث حدث ويقوم بتحميل التغييرات الجديدة وفقًا للذاكرة بحيث يمكنك تغيير الملف النصي في محرر تطبيق/نص واحد ومعرفة التأثير المتغير في تطبيق الويب.
  3. لا يمكنك استخدامه فقط في تطبيق ويب ولكن أيضًا قادرًا على استخدامه في أي تطبيق لسطح المكتب.

شكرًا. طاب يومك.

لا يوجد: لكنني أنشأت فصلًا سهلاً للمساعدة:

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 مع الإسناد
لا تنتمي إلى StackOverflow
scroll top