표준 .ini 파일을 읽고 쓸 수있는 클래스가 .NET 프레임 워크에 있습니까?
[Section]
<keyname>=<value>
...
델파이는 TIniFile
구성 요소를 가지고 있으며 C #과 비슷한 것이 있는지 알고 싶습니다.
표준 .ini 파일을 읽고 쓸 수있는 클래스가 .NET 프레임 워크에 있습니까?
[Section]
<keyname>=<value>
...
델파이는 TIniFile
구성 요소를 가지고 있으며 C #과 비슷한 것이 있는지 알고 싶습니다.
답변:
.NET 프레임 워크 작성자는 INI 파일 대신 XML 기반 구성 파일을 사용하기를 원합니다. 그래서, 그것들을 읽을 수있는 내장 메커니즘이 없습니다.
그러나 사용 가능한 타사 솔루션이 있습니다.
먼저 INI 파일의 제한 사항 에 대한 이 MSDN 블로그 게시물을 읽으십시오 . 필요에 맞는 경우 계속 읽으십시오.
이것은 원본 Windows P / Invoke를 사용하여 작성한 간결한 구현이므로 .NET이 설치된 모든 Windows 버전 (예 : Windows 98-Windows 10)에서 지원됩니다. 본인은이를 공개 도메인으로 공개합니다. 귀하는 저작자 표시없이 상업적으로 자유롭게 사용할 수 있습니다.
IniFile.cs
프로젝트에 호출 된 새 클래스를 추가하십시오 .
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;
}
}
}
다음 3 가지 방법 중 하나로 INI 파일을 엽니 다.
// 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");
다음과 같은 값을 쓸 수 있습니다.
MyIni.Write("DefaultVolume", "100");
MyIni.Write("HomePage", "http://www.google.com");
다음과 같은 파일을 만들려면
[MyProg]
DefaultVolume=100
HomePage=http://www.google.com
INI 파일에서 값을 읽으려면 :
var DefaultVolume = IniFile.Read("DefaultVolume");
var HomePage = IniFile.Read("HomePage");
선택적으로의를 설정할 수 있습니다 [Section]
.
MyIni.Write("DefaultVolume", "100", "Audio");
MyIni.Write("HomePage", "http://www.google.com", "Web");
다음과 같은 파일을 만들려면
[Audio]
DefaultVolume=100
[Web]
HomePage=http://www.google.com
다음과 같이 키가 있는지 확인할 수도 있습니다.
if(!MyIni.KeyExists("DefaultVolume", "Audio"))
{
MyIni.Write("DefaultVolume", "100", "Audio");
}
다음과 같이 키를 삭제할 수 있습니다.
MyIni.DeleteKey("DefaultVolume", "Audio");
다음과 같이 전체 섹션 (모든 키 포함)을 삭제할 수도 있습니다.
MyIni.DeleteSection("Web");
개선 사항이 있으면 언제든지 의견을 남겨주세요!
GetSections()
방법 이 없습니다 .
Path.GetFullPath(IniPath ?? Path.ChangeExtension(Application.ExecutablePath, ".ini"))
입니다.
CodeProject에 대한이 기사 " C #을 사용한 INI 파일 처리 클래스 "가 도움이 될 것입니다.
작성자는 KERNEL32.dll에서 두 가지 기능을 제공하는 C # 클래스 "Ini"를 만들었습니다. 이러한 기능은 다음 WritePrivateProfileString
과 같습니다 GetPrivateProfileString
. 두 개의 네임 스페이스가 필요합니다 : System.Runtime.InteropServices
및 System.Text
.
Ini 클래스를 사용하는 단계
프로젝트 네임 스페이스 정의에 추가
using INI;
이와 같은 INIFile을 만듭니다.
INIFile ini = new INIFile("C:\\test.ini");
사용 IniWriteValue
섹션 또는 사용의 특정 키에 새 값을 작성하는 IniReadValue
특정 섹션의 키에서 값을 읽을 수 있습니다.
참고 : 처음부터 시작하는 경우이 MSDN 문서 : 방법 : C # 프로젝트에 응용 프로그램 구성 파일 추가를 읽을 수 있습니다. 응용 프로그램을 구성하는 더 좋은 방법입니다.
이 간단한 구현을 찾았습니다.
http://bytes.com/topic/net/insights/797169-reading-parsing-ini-file-c
내가 필요한 것에 잘 작동합니다.
사용 방법은 다음과 같습니다.
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();
}
}
코드는 다음과 같습니다.
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);
}
}
joerage의 답변에있는 코드는 고무적입니다.
불행히도 키의 문자 대소 문자를 변경하고 주석을 처리하지 않습니다. 그래서 매우 더러운 INI 파일을 읽을 수있을 정도로 강력해야하며 키를 그대로 가져올 수있는 무언가를 작성했습니다.
섹션, 키 및 값을 저장하고 한 번에 파일을 읽기 위해 대소 문자를 구분하지 않는 중첩 된 문자열 사전 인 LINQ를 사용합니다.
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; }
거기에 넣지 않은 것에 감사드립니다
c #에서 완전히 만든 IniParser 라이브러리를 소개하고 싶습니다. 따라서 모든 OS에 종속성이 없으므로 Mono와 호환됩니다. MIT 라이센스가있는 오픈 소스이므로 모든 코드에서 사용할 수 있습니다.
당신은 할 수 GitHub의에서 소스를 체크 아웃 하고는 NuGet 패키지로도 제공
뻔뻔스런 플러그에 대해 죄송하지만이 답변을 다시 방문하는 사람에게 도움이되기를 바랍니다.
읽기 액세스 만 필요하고 쓰기 액세스는 필요하지 않고 Microsoft.Extensions.Confiuration
ASP.NET Core에 기본적으로 번들로 제공되지만 일반 프로그램에서도 작동합니다)를 사용하는 경우 NuGet 패키지 Microsoft.Extensions.Configuration.Ini
를 사용하여 ini 파일을 구성 설정으로 가져올 수 있습니다.
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddIniFile("SomeConfig.ini", optional: false);
Configuration = builder.Build();
}
Configuration["keyname"]
일반적으로 C # 및 .NET 프레임 워크를 사용하여 응용 프로그램을 만들 때는 INI 파일을 사용하지 않습니다. XML 기반 구성 파일이나 레지스트리에 설정을 저장하는 것이 더 일반적입니다. 그러나 소프트웨어가 레거시 응용 프로그램과 설정을 공유하는 경우 다른 곳에서 정보를 복제하지 않고 구성 파일을 사용하는 것이 더 쉬울 수 있습니다.
.NET 프레임 워크는 INI 파일 사용을 직접 지원하지 않습니다. 그러나 P / Invoke (Platform Invocation Services)와 함께 Windows API 함수를 사용하여 파일에 쓰고 읽을 수 있습니다. 이 링크에서는 INI 파일을 나타내는 클래스를 만들고 Windows API 함수를 사용하여 파일을 조작합니다. 다음 링크를 통해 이동하십시오.
섹션과 다른 dll이없는 간단한 독자를 원한다면 간단한 해결책입니다.
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;
}
}
}
사용 샘플 :
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");
한편 구성 파일 내용 (줄 주석에 # 기호를 지원함) :
#command to run
command = php
#default script
action = index.php
#debug mode
#debug = true
#plain text mode
#plain = false
#icon = favico.ico
이 방법을 시도하십시오 :
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;
}
키가 "-"인 사전을 작성합니다. 다음과 같이로드 할 수 있습니다.
var dict = ParseIniDataWithSections(File.ReadAllLines(fileName));
PeanutButter.INI 는 INI 파일 조작을위한 Nuget 패키지 클래스입니다. 주석을 포함하여 읽기 / 쓰기를 지원합니다. 주석은 쓰기시 유지됩니다. 그것은 합리적으로 인기있는 것으로 보이며, 테스트되고 사용하기 쉽습니다. 또한 완전히 무료이며 오픈 소스입니다.
면책 조항 : 저는 PeanutButter.INI의 저자입니다.
나는 파티에 늦었지만 오늘도 같은 문제가 있었고 다음 구현을 작성했습니다.
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"];
}
이 구현은 찾을 수없는 섹션이나 속성을 처리하지 않습니다. 이를 달성하려면 찾을 수없는 Dictionary<,>
키를 처리 하도록 -class를 확장해야 합니다.
의 인스턴스를 직렬화하기 위해 Dictionary<string, Dictionary<string, string>>
에 .ini
-file, 나는 다음과 같은 코드를 사용 :
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());
CommonLibrary.NET 에는 Ini Parser가 있습니다.
이것은 섹션 / 값을 얻는 데 매우 편리한 다양한 과부하를 가지고 있으며 매우 가볍습니다.
다음은 정규 표현식을 사용하는 자체 버전입니다. 이 코드는 각 섹션 이름이 고유하다고 가정하지만 사실이 아닌 경우 Dictionary를 List로 바꾸는 것이 좋습니다. 이 함수는 ';'부터 시작하여 .ini 파일 주석 달기를 지원합니다. 캐릭터. 섹션이 정상적으로 시작되고 [섹션] 키 값 쌍도 정상적으로 "key = value"가됩니다. 섹션과 동일한 가정-키 이름은 고유합니다.
/// <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;
}
여기 내 수업은 매력처럼 작동합니다.
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();
}
}
정적 클래스이므로 섹션을 읽기 위해 IniFileManager.IniWriteValue를 호출하거나 섹션을 읽기 위해 IniFileManager.IniReadValue를 호출하면됩니다.
전체 오브젝트를 xml에 저장하고 저장된 xml에서 오브젝트를 채울 수 있으므로 xml 파일에서 데이터를 읽고 쓸 수 있습니다. 객체를 조작하는 것이 더 좋습니다.
방법은 다음과 같습니다. XML 파일에 개체 데이터 쓰기 : https://msdn.microsoft.com/en-us/library/ms172873.aspx XML 파일에서 개체 데이터 읽기 : https://msdn.microsoft. com / en-us / library / ms172872.aspx