본문 바로가기

언어/C#

ini file 사용법

출처: http://drt0927.tistory.com/8?category=682501

C# 응용 프로그램을 만들다보면 설정 파일이 필요한 경우가 있다.
이때 ini file을 사용하면 간편하다. 물론 xml로 된 config file도 있지만 ini file이 직관적이고 수정하기 편하다.
구글링을 해보면 C#에서 ini파일을 다루는 여러 내용들이 있지만, 효율적으로 ini file을 관리하고 수정이 용이하게 설명된 내용이 없어 직접 만든 내용을 공유하려 한다.
그렇다고 내가 만든게 짱짱맨 이런 의미는 아니다.

ini file의 구성은
크게 section과 key로 나뉜다.

예를 들면

[Database]
Address="localhost"
Id="root"

[User]
Name="홍길동"
Age="29"

이런 ini file이 있을때 [Database]와 [User]가 section이 되고 Address, id, Name, Age가 key가 된다.

아래 소스를 보면서 하나씩 짚어가보자
 
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
//.. System.ComponentModel.DataAnnotations 는 참조에서 어셈블리를 추가해야 한다.
using System.ComponentModel.DataAnnotations;
using System.Runtime.InteropServices;
using System.Text;
 
namespace ConfigManager
{
    //.. ini file의 정보를 담을 그릇(클래스)
    [Serializable]
    public class MultiKeyDictionary : Dictionary>
    {
        public V this[K1 key1, K2 key2]
        {
            get
            {
                if (!ContainsKey(key1) || !this[key1].ContainsKey(key2))
                {
                    return default(V);
                    //..throw new ArgumentOutOfRangeException();
                }
 
                return base[key1][key2];
            }
            set
            {
                if (!ContainsKey(key1))
                    this[key1] = new Dictionary();
                this[key1][key2] = value;
            }
        }
 
        public void Add(K1 key1, K2 key2, V value)
        {
            if (!ContainsKey(key1))
                this[key1] = new Dictionary();
            this[key1][key2] = value;
        }
 
        public bool ContainsKey(K1 key1, K2 key2)
        {
            return base.ContainsKey(key1) && this[key1].ContainsKey(key2);
        }
 
        public new IEnumerable Values
        {
            get
            {
                return from baseDict in base.Values
                       from baseKey in baseDict.Keys
                       select baseDict[baseKey];
            }
        }
    }
 
    //.. Section 구조
    //.. 추가할 Section이 있을 경우 enum에 추가하고 section name만 정의해주면 된다.          public enum SectionNames
    {
        //.. [Display(Name = "Database")] 에서 Name에 들어가는 문자열이 ini file에 실질적으로 쓰여지는 Section의 이름이다.
        //.. Section Name "Database"

[Display(Name = "Database")] //..해당 이름과 아래 선언된 enum의 이름이 일치해야한다. Database_Section, //.. Section Name "User" [Display(Name = "User")] User_Section, } //.. Database Section의 Key 나열 //.. 추가할 key가 있을 경우 enum에 추가하고 디폴트 값만 정의해주면 된다. public enum Database_Section { //..[Display(Description = "localhost")]에서 Description에 들어가는 문자열은 ini에 key가 없는 경우 디폴트로 들어가는 값이다. //..Default Value : localhost
[Display(Description = "localhost")] //.. Address 그대로 ini file의 key값으로 쓰여진다. Address, //.. Default Value : root [Display(Description = "root")] //.. Id 그대로 ini file의 key값으로 쓰여진다. Id, } //.. User Section의 Key 나열 public enum User_Section { //.. Default Value : 홍길동 [Display(Description = "홍길동")] Name, //.. Default Value : 29 [Display(Description = "29")] Age, } public class ConfigData { //.. ini file의 경로 설정 //.. 원하는 경로와 이름으로 바꿔주면 된다. private string inifilepath = @"C:\Config.ini"; //.. ini file의 정보를 담을 변수 선언 private MultiKeyDictionary _ConfigData = null; //.. ini file을 읽을때 사용하는 함수 [DllImport("kernel32.dll")] private static extern int GetPrivateProfileString( String section, String key, String def, StringBuilder retVal, int Size, String filePath); //.. ini file을 쓸때 사용하는 함수 [DllImport("kernel32.dll")] private static extern long WritePrivateProfileString( String Section, String key, String val, String filePath); public ConfigData() { _ConfigData = new MultiKeyDictionary(); } //.. ConfigData Class내에서 ini file을 쓰기 위한 함수 private void IniWriteValue(String Section, String Key, String Value) { WritePrivateProfileString(Section, Key, Value, inifilepath); } //.. ConfigData Class내에서 ini file을 읽기 위한 함수 private String IniReadValue(String Section, String Key) { StringBuilder temp = new StringBuilder(255); int i = GetPrivateProfileString(Section, Key, "", temp, 255, inifilepath); return temp.ToString(); } //.. 외부에서 ConfigData Class 객체를 이용해 Ini file의 값을 셋팅하기 위한 함수 public void SetConfigData(KeyEnum key, string value) { DisplayAttribute keyAttr = typeof(KeyEnum).GetMember(key.ToString()) .First() .GetCustomAttribute(); SectionNames sectionName = (SectionNames)Enum.Parse(typeof(SectionNames), typeof(KeyEnum).Name); _ConfigData[sectionName][key.ToString()] = value; } //.. 외부에서 ConfigData Class 객체를 이용해 Ini file의 값을 가져오기 위한 함수 public string getConfigData(KeyEnum key) { DisplayAttribute keyAttr = typeof(KeyEnum).GetMember(key.ToString()) .First() .GetCustomAttribute(); SectionNames sectionName = (SectionNames)Enum.Parse(typeof(SectionNames), typeof(KeyEnum).Name); return _ConfigData[sectionName][key.ToString()].ToString(); } //.. Ini file을 저장하기 위한 함수 public void SaveConfigData() { for (int i = 0; i < _ConfigData.Count; i++) { for (int j = 0; j < _ConfigData.ElementAt(i).Value.Count; j++) { string sectionname = _ConfigData.ElementAt(i).Key.ToString(); DisplayAttribute keyAttr = typeof(SectionNames).GetMember(sectionname) .First() .GetCustomAttribute(); string section = keyAttr.Name; string key = _ConfigData.ElementAt(i).Value.ElementAt(j).Key.ToString(); string value = _ConfigData.ElementAt(i).Value.ElementAt(j).Value.ToString(); IniWriteValue( section, //section key, //key value //value ); } } }
//.. Ini file을 읽기 위한 함수 public void ReadConfigData() { foreach (string strSectionName in Enum.GetNames(typeof(SectionNames))) { SectionNames sectionName = (SectionNames)Enum.Parse(typeof(SectionNames), strSectionName); DisplayAttribute sectionAttr = typeof(SectionNames).GetMember(strSectionName) .First() .GetCustomAttribute(); if (!_ConfigData.ContainsKey(sectionName)) _ConfigData.Add(sectionName, new Dictionary()); Type keyType = Type.GetType(string.Format("ConfigManager.{0}", sectionName)); foreach (string strKeyName in Enum.GetNames(keyType)) { DisplayAttribute keyAttr = keyType.GetMember(strKeyName) .First() .GetCustomAttribute(); string value = IniReadValue(sectionAttr.Name, strKeyName); if (!_ConfigData[sectionName].ContainsKey(strKeyName)) //.. 키가 없는 경우 추가 { if (!string.IsNullOrEmpty(value)) //.. ini File에 값이 있다면 ini File 값 입력 _ConfigData[sectionName].Add(strKeyName, value); else //.. ini File에 값이 없다면 Default 값 입력 _ConfigData[sectionName].Add(strKeyName, keyAttr.Description); } else //.. 키가 있는 경우 값 입력 { if (!string.IsNullOrEmpty(value)) //.. ini File에 값이 있다면 ini File 값 입력 _ConfigData[sectionName][strKeyName] = value; else //.. ini File에 값이 없다면 Default 값 입력 _ConfigData[sectionName][strKeyName] = keyAttr.Description; } } } } } } //.. 이렇게 class를 만들었다. 실질적으로 사용하는 방법은 이렇다 using ConfigManager; ConfigData _config = new ConfigData(); // ini file read _config.ReadConfigData(); //.. 각 key에서 값 가져오기 string address = _config.getConfigData(Database_Section.Address); string id = _config.getConfigData(Database_Section.Id); string name = _config.getConfigData(User_Section.Age); string age = _config.getConfigData(User_Section.Name); //.. 각 key에 값 할당 //.. 값을 셋팅만 하지 실질적으로 ini file에 쓰기 위해선 save를 해줘야한다. string address_change = "127.0.0.1"; string id_change = "server"; string name_change = "시나공공"; string age_change = "28"; // 늙었다... _config.SetConfigData(Database_Section.Address, address_change); _config.SetConfigData(Database_Section.Id, id_change); _config.SetConfigData(User_Section.Name, name_change); _config.SetConfigData(User_Section.Age, age_change); //.. ini file save _config.SaveConfigData();



'언어 > C#' 카테고리의 다른 글

STREAMWRITER로 텍스트 로그 남기기  (0) 2018.03.18
Log4Net 사용법  (0) 2018.03.18
C# Tutorials - Create Custom/Professional UI in WinForms app  (0) 2018.03.17
참고사이트  (0) 2018.03.13
Template Match Demo  (0) 2018.03.11