Có lớp nào trong .NET framework có thể đọc / ghi tệp .ini chuẩn không:
[Section]
<keyname>=<value>
...
Delphi có TIniFile
thành phần và tôi muốn biết liệu có gì tương tự cho C # không?
Có lớp nào trong .NET framework có thể đọc / ghi tệp .ini chuẩn không:
[Section]
<keyname>=<value>
...
Delphi có TIniFile
thành phần và tôi muốn biết liệu có gì tương tự cho C # không?
Câu trả lời:
Những người tạo ra .NET framework muốn bạn sử dụng các tệp cấu hình dựa trên XML, thay vì các tệp INI. Vì vậy, không có cơ chế tích hợp để đọc chúng.
Có những giải pháp của bên thứ ba, mặc dù.
Đầu tiên, hãy đọc bài đăng trên blog MSDN này về những hạn chế của các tệp INI . Nếu nó phù hợp với nhu cầu của bạn, hãy đọc tiếp.
Đây là một triển khai ngắn gọn mà tôi đã viết, sử dụng Windows P / Invoke ban đầu, do đó, nó được hỗ trợ bởi tất cả các phiên bản Windows có cài đặt .NET, (ví dụ Windows 98 - Windows 10). Tôi sẽ phát hành nó vào phạm vi công cộng - bạn có thể sử dụng nó một cách thương mại mà không cần ghi công.
Thêm một lớp mới được gọi IniFile.cs
vào dự án của bạn:
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
// Change this to match your program's normal namespace
namespace MyProg
{
class IniFile // revision 11
{
string Path;
string EXE = Assembly.GetExecutingAssembly().GetName().Name;
[DllImport("kernel32", CharSet = CharSet.Unicode)]
static extern long WritePrivateProfileString(string Section, string Key, string Value, string FilePath);
[DllImport("kernel32", CharSet = CharSet.Unicode)]
static extern int GetPrivateProfileString(string Section, string Key, string Default, StringBuilder RetVal, int Size, string FilePath);
public IniFile(string IniPath = null)
{
Path = new FileInfo(IniPath ?? EXE + ".ini").FullName;
}
public string Read(string Key, string Section = null)
{
var RetVal = new StringBuilder(255);
GetPrivateProfileString(Section ?? EXE, Key, "", RetVal, 255, Path);
return RetVal.ToString();
}
public void Write(string Key, string Value, string Section = null)
{
WritePrivateProfileString(Section ?? EXE, Key, Value, Path);
}
public void DeleteKey(string Key, string Section = null)
{
Write(Key, null, Section ?? EXE);
}
public void DeleteSection(string Section = null)
{
Write(null, null, Section ?? EXE);
}
public bool KeyExists(string Key, string Section = null)
{
return Read(Key, Section).Length > 0;
}
}
}
Mở tệp INI theo một trong 3 cách sau:
// Creates or loads an INI file in the same directory as your executable
// named EXE.ini (where EXE is the name of your executable)
var MyIni = new IniFile();
// Or specify a specific name in the current dir
var MyIni = new IniFile("Settings.ini");
// Or specify a specific name in a specific dir
var MyIni = new IniFile(@"C:\Settings.ini");
Bạn có thể viết một số giá trị như vậy:
MyIni.Write("DefaultVolume", "100");
MyIni.Write("HomePage", "http://www.google.com");
Để tạo một tệp như thế này:
[MyProg]
DefaultVolume=100
HomePage=http://www.google.com
Để đọc các giá trị trong tệp INI:
var DefaultVolume = IniFile.Read("DefaultVolume");
var HomePage = IniFile.Read("HomePage");
Tùy chọn, bạn có thể đặt [Section]
:
MyIni.Write("DefaultVolume", "100", "Audio");
MyIni.Write("HomePage", "http://www.google.com", "Web");
Để tạo một tệp như thế này:
[Audio]
DefaultVolume=100
[Web]
HomePage=http://www.google.com
Bạn cũng có thể kiểm tra sự tồn tại của khóa như vậy:
if(!MyIni.KeyExists("DefaultVolume", "Audio"))
{
MyIni.Write("DefaultVolume", "100", "Audio");
}
Bạn có thể xóa một khóa như vậy:
MyIni.DeleteKey("DefaultVolume", "Audio");
Bạn cũng có thể xóa toàn bộ phần (bao gồm tất cả các khóa) như vậy:
MyIni.DeleteSection("Web");
Xin vui lòng bình luận với bất kỳ cải tiến!
GetSections()
phương pháp.
Path.GetFullPath(IniPath ?? Path.ChangeExtension(Application.ExecutablePath, ".ini"))
.
Bài viết này về CodeProject " Một lớp xử lý tệp INI bằng C # " sẽ giúp ích.
Tác giả đã tạo ra một lớp "Ini" C # hiển thị hai hàm từ KERNEL32.dll. Các chức năng này là: WritePrivateProfileString
và GetPrivateProfileString
. Bạn sẽ cần hai không gian tên: System.Runtime.InteropServices
và System.Text
.
Các bước sử dụng lớp Ini
Trong định nghĩa không gian tên dự án của bạn thêm
using INI;
Tạo một INIFile như thế này
INIFile ini = new INIFile("C:\\test.ini");
Sử dụng IniWriteValue
để viết một giá trị mới cho một khóa cụ thể trong một phần hoặc sử dụng IniReadValue
để đọc một giá trị TỪ một khóa trong Phần cụ thể.
Lưu ý: nếu bạn bắt đầu từ đầu, bạn có thể đọc bài viết MSDN này : Cách: Thêm tệp cấu hình ứng dụng vào các dự án C # . Đó là một cách tốt hơn để cấu hình ứng dụng của bạn.
Tôi thấy việc thực hiện đơn giản này:
http://bytes.com/topic/net/insights/797169-reading-parsing-ini-file-c
Hoạt động tốt cho những gì tôi cần.
Đây là cách bạn sử dụng nó:
public class TestParser
{
public static void Main()
{
IniParser parser = new IniParser(@"C:\test.ini");
String newMessage;
newMessage = parser.GetSetting("appsettings", "msgpart1");
newMessage += parser.GetSetting("appsettings", "msgpart2");
newMessage += parser.GetSetting("punctuation", "ex");
//Returns "Hello World!"
Console.WriteLine(newMessage);
Console.ReadLine();
}
}
Đây là mã:
using System;
using System.IO;
using System.Collections;
public class IniParser
{
private Hashtable keyPairs = new Hashtable();
private String iniFilePath;
private struct SectionPair
{
public String Section;
public String Key;
}
/// <summary>
/// Opens the INI file at the given path and enumerates the values in the IniParser.
/// </summary>
/// <param name="iniPath">Full path to INI file.</param>
public IniParser(String iniPath)
{
TextReader iniFile = null;
String strLine = null;
String currentRoot = null;
String[] keyPair = null;
iniFilePath = iniPath;
if (File.Exists(iniPath))
{
try
{
iniFile = new StreamReader(iniPath);
strLine = iniFile.ReadLine();
while (strLine != null)
{
strLine = strLine.Trim().ToUpper();
if (strLine != "")
{
if (strLine.StartsWith("[") && strLine.EndsWith("]"))
{
currentRoot = strLine.Substring(1, strLine.Length - 2);
}
else
{
keyPair = strLine.Split(new char[] { '=' }, 2);
SectionPair sectionPair;
String value = null;
if (currentRoot == null)
currentRoot = "ROOT";
sectionPair.Section = currentRoot;
sectionPair.Key = keyPair[0];
if (keyPair.Length > 1)
value = keyPair[1];
keyPairs.Add(sectionPair, value);
}
}
strLine = iniFile.ReadLine();
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (iniFile != null)
iniFile.Close();
}
}
else
throw new FileNotFoundException("Unable to locate " + iniPath);
}
/// <summary>
/// Returns the value for the given section, key pair.
/// </summary>
/// <param name="sectionName">Section name.</param>
/// <param name="settingName">Key name.</param>
public String GetSetting(String sectionName, String settingName)
{
SectionPair sectionPair;
sectionPair.Section = sectionName.ToUpper();
sectionPair.Key = settingName.ToUpper();
return (String)keyPairs[sectionPair];
}
/// <summary>
/// Enumerates all lines for given section.
/// </summary>
/// <param name="sectionName">Section to enum.</param>
public String[] EnumSection(String sectionName)
{
ArrayList tmpArray = new ArrayList();
foreach (SectionPair pair in keyPairs.Keys)
{
if (pair.Section == sectionName.ToUpper())
tmpArray.Add(pair.Key);
}
return (String[])tmpArray.ToArray(typeof(String));
}
/// <summary>
/// Adds or replaces a setting to the table to be saved.
/// </summary>
/// <param name="sectionName">Section to add under.</param>
/// <param name="settingName">Key name to add.</param>
/// <param name="settingValue">Value of key.</param>
public void AddSetting(String sectionName, String settingName, String settingValue)
{
SectionPair sectionPair;
sectionPair.Section = sectionName.ToUpper();
sectionPair.Key = settingName.ToUpper();
if (keyPairs.ContainsKey(sectionPair))
keyPairs.Remove(sectionPair);
keyPairs.Add(sectionPair, settingValue);
}
/// <summary>
/// Adds or replaces a setting to the table to be saved with a null value.
/// </summary>
/// <param name="sectionName">Section to add under.</param>
/// <param name="settingName">Key name to add.</param>
public void AddSetting(String sectionName, String settingName)
{
AddSetting(sectionName, settingName, null);
}
/// <summary>
/// Remove a setting.
/// </summary>
/// <param name="sectionName">Section to add under.</param>
/// <param name="settingName">Key name to add.</param>
public void DeleteSetting(String sectionName, String settingName)
{
SectionPair sectionPair;
sectionPair.Section = sectionName.ToUpper();
sectionPair.Key = settingName.ToUpper();
if (keyPairs.ContainsKey(sectionPair))
keyPairs.Remove(sectionPair);
}
/// <summary>
/// Save settings to new file.
/// </summary>
/// <param name="newFilePath">New file path.</param>
public void SaveSettings(String newFilePath)
{
ArrayList sections = new ArrayList();
String tmpValue = "";
String strToSave = "";
foreach (SectionPair sectionPair in keyPairs.Keys)
{
if (!sections.Contains(sectionPair.Section))
sections.Add(sectionPair.Section);
}
foreach (String section in sections)
{
strToSave += ("[" + section + "]\r\n");
foreach (SectionPair sectionPair in keyPairs.Keys)
{
if (sectionPair.Section == section)
{
tmpValue = (String)keyPairs[sectionPair];
if (tmpValue != null)
tmpValue = "=" + tmpValue;
strToSave += (sectionPair.Key + tmpValue + "\r\n");
}
}
strToSave += "\r\n";
}
try
{
TextWriter tw = new StreamWriter(newFilePath);
tw.Write(strToSave);
tw.Close();
}
catch (Exception ex)
{
throw ex;
}
}
/// <summary>
/// Save settings back to ini file.
/// </summary>
public void SaveSettings()
{
SaveSettings(iniFilePath);
}
}
Các mã trong câu trả lời của joerage là cảm hứng.
Thật không may, nó thay đổi vỏ ký tự của các phím và không xử lý các bình luận. Vì vậy, tôi đã viết một cái gì đó đủ mạnh để đọc (chỉ) các tệp INI rất bẩn và cho phép truy xuất các khóa như hiện tại.
Nó sử dụng một số LINQ, một từ điển chuỗi không nhạy cảm trường hợp lồng nhau để lưu trữ các phần, khóa và giá trị và đọc tệp trong một lần.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
class IniReader
{
Dictionary<string, Dictionary<string, string>> ini = new Dictionary<string, Dictionary<string, string>>(StringComparer.InvariantCultureIgnoreCase);
public IniReader(string file)
{
var txt = File.ReadAllText(file);
Dictionary<string, string> currentSection = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
ini[""] = currentSection;
foreach(var line in txt.Split(new[]{"\n"}, StringSplitOptions.RemoveEmptyEntries)
.Where(t => !string.IsNullOrWhiteSpace(t))
.Select(t => t.Trim()))
{
if (line.StartsWith(";"))
continue;
if (line.StartsWith("[") && line.EndsWith("]"))
{
currentSection = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
ini[line.Substring(1, line.LastIndexOf("]") - 1)] = currentSection;
continue;
}
var idx = line.IndexOf("=");
if (idx == -1)
currentSection[line] = "";
else
currentSection[line.Substring(0, idx)] = line.Substring(idx + 1);
}
}
public string GetValue(string key)
{
return GetValue(key, "", "");
}
public string GetValue(string key, string section)
{
return GetValue(key, section, "");
}
public string GetValue(string key, string section, string @default)
{
if (!ini.ContainsKey(section))
return @default;
if (!ini[section].ContainsKey(key))
return @default;
return ini[section][key];
}
public string[] GetKeys(string section)
{
if (!ini.ContainsKey(section))
return new string[0];
return ini[section].Keys.ToArray();
}
public string[] GetSections()
{
return ini.Keys.Where(t => t != "").ToArray();
}
}
catch (Exception ex) { throw ex; }
ở đó
Tôi muốn giới thiệu một thư viện IniParser mà tôi đã tạo hoàn toàn trong c #, vì vậy nó không chứa phụ thuộc trong bất kỳ HĐH nào, điều này làm cho nó tương thích Mono. Nguồn mở với giấy phép MIT - vì vậy nó có thể được sử dụng trong bất kỳ mã nào.
Bạn có thể kiểm tra nguồn trong GitHub và nó cũng có sẵn dưới dạng gói NuGet
Đó là cấu hình nặng , và thực sự đơn giản để sử dụng .
Xin lỗi vì phích cắm không biết xấu hổ nhưng tôi hy vọng nó có thể giúp đỡ bất cứ ai xem lại câu trả lời này.
Nếu bạn chỉ cần truy cập đọc và không truy cập ghi và bạn đang sử dụng Microsoft.Extensions.Confiuration
(đi kèm theo mặc định với ASP.NET Core nhưng cũng hoạt động với các chương trình thông thường), bạn có thể sử dụng gói NuGet Microsoft.Extensions.Configuration.Ini
để nhập tệp ini vào cài đặt cấu hình của mình.
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddIniFile("SomeConfig.ini", optional: false);
Configuration = builder.Build();
}
Configuration["keyname"]
Thông thường, khi bạn tạo các ứng dụng bằng C # và .NET framework, bạn sẽ không sử dụng các tệp INI. Việc lưu trữ các cài đặt trong tệp cấu hình dựa trên XML hoặc trong sổ đăng ký là phổ biến hơn. Tuy nhiên, nếu phần mềm của bạn chia sẻ cài đặt với ứng dụng cũ, có thể sử dụng tệp cấu hình của nó dễ dàng hơn thay vì sao chép thông tin ở nơi khác.
.NET framework không hỗ trợ trực tiếp sử dụng các tệp INI. Tuy nhiên, bạn có thể sử dụng các chức năng API của Windows với Dịch vụ gọi nền tảng (P / Gọi) để ghi và đọc từ các tệp. Trong liên kết này, chúng tôi tạo một lớp đại diện cho các tệp INI và sử dụng các hàm API của Windows để thao tác chúng. Vui lòng đi qua liên kết sau.
Nếu bạn chỉ muốn một người đọc đơn giản không có phần và bất kỳ dll nào khác ở đây là giải pháp đơn giản:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Tool
{
public class Config
{
Dictionary <string, string> values;
public Config (string path)
{
values = File.ReadLines(path)
.Where(line => (!String.IsNullOrWhiteSpace(line) && !line.StartsWith("#")))
.Select(line => line.Split(new char[] { '=' }, 2, 0))
.ToDictionary(parts => parts[0].Trim(), parts => parts.Length>1?parts[1].Trim():null);
}
public string Value (string name, string value=null)
{
if (values!=null && values.ContainsKey(name))
{
return values[name];
}
return value;
}
}
}
Mẫu sử dụng:
file = new Tool.Config (Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\config.ini");
command = file.Value ("command");
action = file.Value ("action");
string value;
//second parameter is default value if no key found with this name
value = file.Value("debug","true");
this.debug = (value.ToLower()=="true" || value== "1");
value = file.Value("plain", "false");
this.plain = (value.ToLower() == "true" || value == "1");
Cấu hình nội dung tệp trong khi đó (như bạn thấy hỗ trợ biểu tượng # cho nhận xét dòng):
#command to run
command = php
#default script
action = index.php
#debug mode
#debug = true
#plain text mode
#plain = false
#icon = favico.ico
Hãy thử phương pháp này:
public static Dictionary<string, string> ParseIniDataWithSections(string[] iniData)
{
var dict = new Dictionary<string, string>();
var rows = iniData.Where(t =>
!String.IsNullOrEmpty(t.Trim()) && !t.StartsWith(";") && (t.Contains('[') || t.Contains('=')));
if (rows == null || rows.Count() == 0) return dict;
string section = "";
foreach (string row in rows)
{
string rw = row.TrimStart();
if (rw.StartsWith("["))
section = rw.TrimStart('[').TrimEnd(']');
else
{
int index = rw.IndexOf('=');
dict[section + "-" + rw.Substring(0, index).Trim()] = rw.Substring(index+1).Trim().Trim('"');
}
}
return dict;
}
Nó tạo ra từ điển trong đó khóa là "-". Bạn có thể tải nó như thế này:
var dict = ParseIniDataWithSections(File.ReadAllLines(fileName));
PeanutButter.INI là lớp đóng gói Nuget để thao tác với các tệp INI. Nó hỗ trợ đọc / ghi, bao gồm cả ý kiến - ý kiến của bạn được lưu giữ trên văn bản. Nó dường như là phổ biến hợp lý, được thử nghiệm và dễ sử dụng. Nó cũng hoàn toàn miễn phí và là nguồn mở.
Tuyên bố miễn trừ trách nhiệm: Tôi là tác giả của PeanutButter.INI.
Tôi đến trễ để tham gia bữa tiệc, nhưng hôm nay tôi cũng gặp vấn đề tương tự và tôi đã viết cách thực hiện như sau:
using System.Text.RegularExpressions;
static bool match(this string str, string pat, out Match m) =>
(m = Regex.Match(str, pat, RegexOptions.IgnoreCase)).Success;
static void Main()
{
Dictionary<string, Dictionary<string, string>> ini = new Dictionary<string, Dictionary<string, string>>();
string section = "";
foreach (string line in File.ReadAllLines(.........)) // read from file
{
string ln = (line.Contains('#') ? line.Remove(line.IndexOf('#')) : line).Trim();
if (ln.match(@"^[ \t]*\[(?<sec>[\w\-]+)\]", out Match m))
section = m.Groups["sec"].ToString();
else if (ln.match(@"^[ \t]*(?<prop>[\w\-]+)\=(?<val>.*)", out m))
{
if (!ini.ContainsKey(section))
ini[section] = new Dictionary<string, string>();
ini[section][m.Groups["prop"].ToString()] = m.Groups["val"].ToString();
}
}
// access the ini file as follows:
string content = ini["section"]["property"];
}
Cần lưu ý rằng việc triển khai này không xử lý các phần hoặc thuộc tính không được tìm thấy. Để đạt được điều này, bạn nên mở rộng Dictionary<,>
lớp để xử lý các khóa không có căn cứ.
Để tuần tự hóa một thể hiện của Dictionary<string, Dictionary<string, string>>
một .ini
-file, tôi sử dụng đoạn mã sau:
string targetpath = .........;
Dictionary<string, Dictionary<string, string>> ini = ........;
StringBuilder sb = new StringBuilder();
foreach (string section in ini.Keys)
{
sb.AppendLine($"[{section}]");
foreach (string property in ini[section].Keys)
sb.AppendLine($"{property}={ini[section][property]");
}
File.WriteAllText(targetpath, sb.ToString());
Có một Trình phân tích cú pháp Ini có sẵn trong CommonL Library.NET
Điều này có quá tải rất thuận tiện khác nhau để có được các phần / giá trị và trọng lượng rất nhẹ.
Đây là phiên bản của riêng tôi, sử dụng các biểu thức thông thường. Mã này giả định rằng mỗi tên phần là duy nhất - tuy nhiên điều này không đúng - việc thay thế Từ điển bằng Danh sách là điều hợp lý. Hàm này hỗ trợ nhận xét tệp .ini, bắt đầu từ ';' tính cách. Phần bắt đầu bình thường [phần] và các cặp giá trị khóa cũng thường xuất hiện "key = value". Giả định tương tự như đối với các phần - tên khóa là duy nhất.
/// <summary>
/// Loads .ini file into dictionary.
/// </summary>
public static Dictionary<String, Dictionary<String, String>> loadIni(String file)
{
Dictionary<String, Dictionary<String, String>> d = new Dictionary<string, Dictionary<string, string>>();
String ini = File.ReadAllText(file);
// Remove comments, preserve linefeeds, if end-user needs to count line number.
ini = Regex.Replace(ini, @"^\s*;.*$", "", RegexOptions.Multiline);
// Pick up all lines from first section to another section
foreach (Match m in Regex.Matches(ini, "(^|[\r\n])\\[([^\r\n]*)\\][\r\n]+(.*?)(\\[([^\r\n]*)\\][\r\n]+|$)", RegexOptions.Singleline))
{
String sectionName = m.Groups[2].Value;
Dictionary<String, String> lines = new Dictionary<String, String>();
// Pick up "key = value" kind of syntax.
foreach (Match l in Regex.Matches(ini, @"^\s*(.*?)\s*=\s*(.*?)\s*$", RegexOptions.Multiline))
{
String key = l.Groups[1].Value;
String value = l.Groups[2].Value;
// Open up quotation if any.
value = Regex.Replace(value, "^\"(.*)\"$", "$1");
if (!lines.ContainsKey(key))
lines[key] = value;
}
if (!d.ContainsKey(sectionName))
d[sectionName] = lines;
}
return d;
}
Đây là lớp học của tôi, hoạt động như một cơ duyên:
public static class IniFileManager
{
[DllImport("kernel32")]
private static extern long WritePrivateProfileString(string section,
string key, string val, string filePath);
[DllImport("kernel32")]
private static extern int GetPrivateProfileString(string section,
string key, string def, StringBuilder retVal,
int size, string filePath);
[DllImport("kernel32.dll")]
private static extern int GetPrivateProfileSection(string lpAppName,
byte[] lpszReturnBuffer, int nSize, string lpFileName);
/// <summary>
/// Write Data to the INI File
/// </summary>
/// <PARAM name="Section"></PARAM>
/// Section name
/// <PARAM name="Key"></PARAM>
/// Key Name
/// <PARAM name="Value"></PARAM>
/// Value Name
public static void IniWriteValue(string sPath,string Section, string Key, string Value)
{
WritePrivateProfileString(Section, Key, Value, sPath);
}
/// <summary>
/// Read Data Value From the Ini File
/// </summary>
/// <PARAM name="Section"></PARAM>
/// <PARAM name="Key"></PARAM>
/// <PARAM name="Path"></PARAM>
/// <returns></returns>
public static string IniReadValue(string sPath,string Section, string Key)
{
StringBuilder temp = new StringBuilder(255);
int i = GetPrivateProfileString(Section, Key, "", temp,
255, sPath);
return temp.ToString();
}
}
Việc sử dụng là obviouse vì nó là một lớp tĩnh, chỉ cần gọi IniFileManager.IniWriteValue để đọc một phần hoặc IniFileManager.IniReadValue để đọc một phần.
Bạn nên đọc và ghi dữ liệu từ các tệp xml vì bạn có thể lưu toàn bộ một đối tượng vào xml và bạn cũng có thể điền một đối tượng từ xml đã lưu. Nó là tốt hơn một dễ dàng để thao tác các đối tượng.
Dưới đây là cách thực hiện: Ghi dữ liệu đối tượng vào tệp XML: https://msdn.microsoft.com/en-us/l Library / ms172873.aspx Đọc dữ liệu đối tượng từ tệp XML: https://msdn.microsoft. com / en-us / thư viện / ms172872.aspx