2012-06-15

C# load INI file


사용자의 설정을 기억할 목적으로 ini파일을 사용해 보고자 만들었다.
INI파일을 로드하고, 원하는 항목을 return 하는 기능을 구현했다.
일부러 이번엔 다른 사람의 코드를 먼저 보지않고, 내 나름대로 작성한 후에 봤다.

작성 후, 다른 사람의 소스를 보니 굉장히 간결했다. 아직 가야할 길이 먼 것 같다.
(비교: http://www.codeproject.com/Articles/1966/An-INI-file-handling-class-using-C)
검색된 소스는 GetPrivateProfileString, WritePrivateProfileString라는 API를 사용했다.


 
using System.Collections.Generic;
using System.Collections;
using System.IO;
using System.Diagnostics;
namespace automating_system_report
{

        #region INISTRUCT
        public class INISTRUCT  //INI파일의 한 줄의 내용을 저장할 class. List로 사용함.
        {
            public string lvar; // 왼쪽 문자열(상수이름) 
            public string rvar; // 오른쪽 문자열(상수값)
            public INISTRUCT(string inputLvar, string inputRvar)
            {
                lvar = inputLvar;
                rvar = inputRvar;
            }
        }
        #endregion

    #region INILoader
    /// 
    /// INI 파일을 읽어 , 데이터 이름과 데이터 값을 listINI 리스트에 저장하는 클래스.
    /// INILoader를 선언하고, LoadINIFile("filename") 메쏘드를 실행하면,
    /// INI파일의 값들을 클래스 내의 listINI 리스트에 저장한다.
    /// 
    public class INILoader
    {        
        #region globar var
        private  string matchString; //Predicate함수로 전달할 목적으로 전역 변수를 사용함.
        #endregion

        #region public member
        //INISTRUCT의 List
        public List listINI = new List();
        
        #endregion
        
        #region public method
        // INI파일을 로딩, 
        public bool LoadINIFile(string filename)
        {
            try
            {
                if (File.Exists(filename))
                {
                    FileStream fs = File.OpenRead(filename);
                    StreamReader sr = new StreamReader(fs);
                    while (sr.Peek() > -1) // Peek은  문자가 더 이상 없으면 반환 값은 -1 이다.
                    {
                        FillINISTRUCT(sr.ReadLine());  // FillINIStruct로 전역 리스트 listINI에 값을 저장함.
                    }
                    sr.Close();
                    fs.Close();
                    return true;
                }
                return false;
            }
            catch { return false; }

        }
        public void SaveINIFile(string filename)
        {
            try
            {
                /* FileStream fs=new FileStream(filename);
                 * StreamWriter sw=new StreamWriter(fs);
                 * 이렇게 해서 쓰면, 생성된 파일 끝부분에 이전의 쓰레기 값이 남았다...왜 그런지는 알아봐야함.
                 * 이미 있는 파일에 덮어쓰기 할 때, 이전 값이 더 클 경우 쓰레기 값이 남는 것으로 보임.
                 */
                StreamWriter sw = new StreamWriter(filename,false,  System.Text.Encoding.Unicode);
                foreach (INISTRUCT i in listINI)
                {
                    sw.WriteLine(@i.lvar + " = " + @i.rvar);
                    //Trace.WriteLine("sw:"+i.lvar + "," + i.rvar);
                }
                sw.Close();

            }
            catch { }
        }
        public bool AddINI(string inistr)
        {
            INISTRUCT inputINI = StringToINISTRUCT(inistr);
            for (int i = 0; i < listINI.Count; i++)
            {
                if (listINI[i].lvar == inputINI.lvar) //이미 해당 lvar가 있으면 rvar를 수정
                {
                    Trace.WriteLine(listINI[i].rvar+"->"+inputINI.rvar);
                    listINI[i].rvar = inputINI.rvar;
                    
                    return true;
                }
            }
            listINI.Add(inputINI); // 기존에 없던 rvar값이면 추가.
            return true;
        }
        public string FindValue(string valueName)
        {
            //valueName의 lvar를 찾아 rvar를 return
            matchString = valueName;
            try
            {
                INISTRUCT pickINI = listINI.Find(MatchingPredicate); // MatchingPredicate의 주석 참조.
                return pickINI.rvar; //"valueName = matchString = 찾고자 하는 lvar의 이름"으로 찾은 rvar의 값
            }
            catch 
            {
                return null; // lvar에 valueName없음.
            }
        }

        #endregion

        #region private method
        private bool MatchingPredicate(INISTRUCT p)
        {
            /// http://msdn.microsoft.com/ko-kr/library/x0b5b5bc.aspx
            /// MSDN에서는 Predicate 함수를 static으로 선언하고 있어, matchString도 static으로 선언해야 한다...
            /// Predicate함수와 matchString을 둘 다 static에서 해제 했음.
            /// 람다식을 이용하면 더 깔끔한(전역변수 남용 없이, predicate 선언 없이..) 구현할 수 있을 것 같다.
            return (matchString == p.lvar);
        }

        /// 
        /// INI파일에서 읽어들인 레코드를 Substring, Trim 하는 함수
        /// 
        /// "상수이름 = 값" 형식의 문자열
        private void FillINISTRUCT(string tmpiniString)
        {
                //Trim된 Rvar와 Lvar를 리스트에 Add()
                INISTRUCT tmpinistruct = StringToINISTRUCT(tmpiniString);  
                listINI.Add(tmpinistruct);
        }
        public INISTRUCT StringToINISTRUCT(string inistr)
        {
            int locateEqualMark; // "=" 마크 위치
            int locateRvarStart, locateRvarEnd; // rvar substring 위치
            string tmpLvar; // lvar를 저장할 임시 변수
            string tmpRvar; // rvar를 저장할 임시 변수 
            //substring 할 위치
            locateEqualMark = inistr.IndexOf('=');
            locateRvarStart = locateEqualMark + 1;
            locateRvarEnd = inistr.Length - locateEqualMark - 1;
            //substring 
            if (locateEqualMark == -1)
            {return null;}
            // Trim하기 전의 임시변수
            tmpLvar = inistr.Substring(0, locateEqualMark);
            tmpRvar = inistr.Substring(locateRvarStart, locateRvarEnd);
            //앞뒤 공백제거 "    some string" or "some string        " => "some string"
            tmpLvar = tmpLvar.Trim();
            tmpRvar = tmpRvar.Trim();
            return  new INISTRUCT(tmpLvar, tmpRvar);
        }
        #endregion
    }
    #endregion
}
//

테스트 코드

 
        #region global var
        INILoader ini = new INILoader();
        #endregion

        #region const var
        public const string inifilename = @"C:\windows\win.ini";
        #endregion

        public DlgOption()
        {
            InitializeComponent();
            ini.LoadINIFile(inifilename);
            //테스트 foreach
            foreach (INISTRUCT s in ini.listINI)
            {
                string traceString;
                traceString=string.Format("Trace: \"{0}\", \"{1}\"",s.lvar,s.rvar);
                Trace.WriteLine(traceString);
            }
            Trace.WriteLine("find="+ini.FindValue("mp3"));
            Trace.WriteLine("find=" + ini.FindValue("MP3"));
        }
/* 테스트
Trace: "CMC", "1"
Trace: "MAPI", "1"
Trace: "MAPIX", "1"
Trace: "MAPIXVER", "1.0.0.1"
Trace: "OLEMessaging", "1"
find=MPEGVideo <- "MP3" 검색결과
'System.NullReferenceException' 형식의 첫째 예외가 automating_system_report.exe에서 발생했습니다.
find= <- 찾는 항목 없음 "mp3" 검색결과...
*/
//

댓글 없음:

댓글 쓰기