저번 포스팅에서는 C#에서 WINAPI 함수 중 INI 파일 조작 함수를 Wrapping한 클래스에 대해 살펴 보았습니다.
이번 시간에는 실제 ini 파일을 조작 하기 위한 클래스를 소개 해 드릴까 합니다.
급하게 만든거라 허접하더래도 이해해 주시고, 그럼 레지스트리 형식의 INI 파일을 제어하는데 필요한 기능을 정의한 interface부터 살펴 보겠습니다.(첨부파일에 몇가지 내용은 본 포스팅에 게시되지 않을 수 있습니다.)
/// <summary> |
/// Registry 형식의 파일 조작에 필요한 기능을 제공합니다. |
/// </summary> |
public interface IPrivateProfileProvider |
{ |
/// <summary> |
/// 섹션 리스트를 가져옵니다. |
/// </summary> |
/// <returns>섹션 문자열 배열입니다.</returns> |
string[] GetSectionNames(); |
/// <summary> |
/// 섹션을 이용해 키와 값의 Pair 배열을 가져 옵니다. |
/// </summary> |
/// <param name="szSection">섹션 문자열입니다.</param> |
/// <returns>키와 값의 Pair 배열입니다. 하나의 Pair는 '키=값'의 형식으로 가져오게 됩니다.</returns> |
string[] GetPairsBySection(string szSection); |
/// <summary> |
/// 섹션을 삭제합니다. |
/// </summary> |
/// <param name="szSection"></param> |
void DeleteSection(string szSection); |
/// <summary> |
/// 섹션명 밑에 있는 키를 삭제 합니다. |
/// </summary> |
/// <param name="szSection">섹션명입니다.</param> |
/// <param name="szKey">삭제할 키입니다.</param> |
bool DeleteKey(string szSection, string szKey); |
/// <summary> |
/// 섹션명 밑에 키와 값을 파일에 씁니다. |
/// </summary> |
/// <param name="szSection">섹션명입니다.</param> |
/// <param name="szKey">키입니다.</param> |
/// <param name="szValue">값입니다.</param> |
bool WritePair(string szSection, string szKey, string szValue); |
왜 클래스를 정의 안하고 인터페이스를 정의했는지에 대해서는 언급 하지 않겠습니다. OOP 사상의 이해가 필요하기 때문에, '적어도 이 기능들을 정의 해야 INI 제어 클래스라 할 수 있다'라고만 말씀 드리고 넘어가도록 하겠습니다.
인터페이스에 정의된 함수의 역할은 위의 주석을 통해 아실 수 있으리라 생각되며, 이 인터페이스를 상속 받은 Win32Reg 클래스 중 몇 함수들의 동작에 대해 살펴 보겠습니다.
먼저 샘플 INI를 정의해 보죠
INI_Chapter1을 읽어 보셨다면 Section, Key, Value가 어떤 것인지 아실 수 있을 겁니다.
그럼 현재 프로그램 상에서 저 INI파일에 접근하지 않았다고 가정 한다면, 1번째 작업으로 섹션 리스트를 얻어와야 합니다.
/// <summary> |
/// 섹션 리스트를 가져옵니다. |
/// </summary> |
/// <returns>섹션 문자열 배열입니다.</returns> |
public string[] GetSectionNames() |
{ |
if (!System.IO.File.Exists(_szFileName)) throw new FileNotFoundException(); |
byte[] bSection = new byte[SectionBufferSize]; |
if (Win32RegNative.GetPrivateProfileSectionNames(bSection, SectionBufferSize, _szFileName) <= 0) |
{ |
return null; |
} |
return System.Text.Encoding.Default.GetString(bSection).Split(new char[1] { '\0' }, StringSplitOptions.RemoveEmptyEntries); |
} |
Win32RegNative.GetPrivateProfileSectionNames 함수의 1번째 인자가 섹션 리스트를 가져 오기 위한 버퍼인데, 버퍼에는 다음의 형태로 값이 들어오게 됩니다.
ZONE1\0ZONE2\0\0\0 |
이것을 일반적인 String으로 받게 되면 널문자를 포함하고 있기 때문에 ZONE1까지만 들어오게 됩니다. 하여 byte 배열로 받아 이를 다시 String으로 변환하는 작업을 해 줘야 되죠.
return System.Text.Encoding.Default.GetString(bSection).Split(new char[1] { '\0' }, StringSplitOptions.RemoveEmptyEntries); |
위 코드는 byte 배열인 bSection을 .Net Framework의 Encoding 클래스를 통해 String으로 변환하며, 뒤의 작업은 널 문자를 기준으로 문자열을 나누어 실제적으로 섹션 리스트를 String 배열에 담는 작업을 하게 됩니다.
이렇게 섹션을 모두 읽은 다음, 섹션 밑에 있는 키와 값 쌍을 얻어 오는 작업을 합니다.
public string[] GetPairsBySection(string szSection) |
{ |
if (!System.IO.File.Exists(_szFileName)) throw new FileNotFoundException(); |
byte[] bPair = new byte[PairBufferSize]; |
if (Win32RegNative.GetPrivateProfileSection(szSection, bPair, PairBufferSize, _szFileName) <= 0) |
{ |
return null; |
} |
return System.Text.Encoding.Default.GetString(bPair).Split(new char[1] { '\0' }, StringSplitOptions.RemoveEmptyEntries); |
} |
위 함수의 인자로 "ZONE1"이 들어갔다고 가정을 하면 Win32RegNative.GetPrivateProfileSection 함수의 2번째 인자인 bPair에는 다음과 같이 값이 들어갑니다.
Name=Tom\0Age=20\0Phone=0101111234\0\0\0
이 버퍼도 마찬가지로 섹션 리스트와 같이 처리하면 됩니다. 하지만 키와 값이 같이 있는 쌍(Pair)의 형태로 들어오기 때문에, '='문자를 기준으로 키와 값을 분리 하는 작업을 해야 합니다. 다음과 같이 말이죠.
public static string[] SplitPair(string szSource) |
{ |
string[] szTemp = szSource.Split(new char[1] { '=' }, StringSplitOptions.RemoveEmptyEntries); |
if (szTemp.Length > 2 || szTemp.Length <= 0) |
throw new ArgumentOutOfRangeException |
(szSource, |
"'키=값'으로 된 문자열 형태가 아닙니다."); |
return szTemp; |
} |
아래의 섹션도 마찬가지의 작업을 하시면 되겠습니다.
본 포스팅은 타 블로그나 카페에 복사/스크랩 하는 것을 금지합니다