출처: http://www.digipine.com/programming/4337/page/1
string fileContent = null;
using ( StreamReader sr = new StreamReader( filePath ) )
{
fileContent = sr.ReadToEnd();
sr.Close();
}
.NET 에서는 문자열 처리를 명시적으로 지정하지 않는 한, 기본적으로 "System.Text.UTF8Encoding" 으로 처리를 합니다.
문제는 거기서 발생을 하지요. 해당 HTML 텍스트 한글 파일은 메모장에서 "ASCII" 형식으로 저장된 것이었고, 디코딩을 UTF-8 로 해버리니
당연히 깨질 수 밖에 없습니다.
한글이 포함된 ASCII 코드를 정상적으로 읽어들이기 위해서는 인코딩을 지정해야 합니다.
StreamReader 의 두번째 인자에는 바로 그 인코딩 방식을 지정할 수가 있죠.
우리가 아는 것처럼 "KS_C_5601-1987" 인코딩 방식을 지정해야 합니다.
다음과 같은 코드로.
using ( StreamReader sr = new StreamReader( filePath, Encoding.GetEncoding( "ks_c_5601-1987" ) ) )
{
fileContent = sr.ReadToEnd();
sr.Close();
}
명시적인 Encoding 문자열 지정대신에, Encoding.Default 를 지정해도 됩니다.
시스템 레벨로 설정된 (제어판의 Regional Settings) code page 값이 한글 윈도우즈에서는 기본적으로 "KS_C_5601-1987" 이기 때문입니다.
하지만, 여기서 끝이 아니죠. 만약 해당 파일이 utf-8 또는 unicode 로 인코딩된 텍스트 파일이라면?
당연히 위의 코드로 읽어들이게 되면 역시 한글이 깨지게 됩니다.
Unicode 또는 UTF-8 등의 텍스트 파일은 그 인코딩 방법을 표시하기 위해, 파일의 최초 2~3 바이트에 BOM(byte order mark)를 표시해 둡니다.
utf-8 로 인코딩된 텍스트 파일을 윈도우즈의 "메모장"으로 열어보면 그러한 표시를 생략하고 순수 텍스트만 보여주지만,
2진 파일 형식으로 볼 수 있는 hexa 에디터등을 통해서 보게 되면, 최초 2~3바이트의 내용이 인코딩에 따라서 달라지는 것을 확인할 수 있습니다.
UTF-8: EF BB BF
Unicode: FF FE
실제로, BOM 을 통한 디코딩을 지원하지 않는 Editor 로 UTF-8 인코딩된 파일을 열게 되면,
최초 3byte 를 깨진 텍스트로 출력해 주는 것을 볼 수 있습니다.
아뭏든... 그렇다면, 우리도 BOM 을 읽어서 상황에 따라 StreamReader 의 2번째 인자에
각각 해당하는 인코딩을 넣어주면 되겠지요. 아마도 C++ 이었다면 틀림없이 그렇게 해야 했을 것입니다.
하지만, 우리의 "친절한 .NET 씨"(이 표현은 Loner(http://simpleisbest.net)에서 빌려옴) 는
그런 작업을 모두 해놓았습니다. 바로 StreamReader 의 3번째 인자에서 그러한 역할을 대신해 줍니다.
public StreamReader(..., bool detectEncodingFromByteOrderMarks);
매개변수 이름 부터 그런 태생임을 짐작하게 해줍니다.
해당 값을 true 로 전달하면 BOM 마크가 없는 - 예를 들어 ANSI 파일 - 경우에는 2번째 인자에서
지정한 Encoding 방식으로 인식해서 디코딩을 하지만, BOM 이 있으면 거기서 지정된 Encoding
방식으로 되어 있다고 인식해서 디코딩을 하게 됩니다.
그러니... 앞으로 국내에서의 .NET 개발자들은 텍스트 파일을 로딩하기 위한 표준 코드를
다음과 같이 해야 합니다.
using ( StreamReader sr = new StreamReader( filePath, Encoding.GetEncoding( "ks_c_5601-1987" ), true ) )
{
fileContent = sr.ReadToEnd();
sr.Close();
}
또는
using ( StreamReader sr = new StreamReader( filePath, Encoding.Default, true ) )
{
fileContent = sr.ReadToEnd();
sr.Close();
}
두 가지 모두, 경우에 따라서 논란의 여지가 있지만...
적어도 한글 윈도우즈에서 호스팅 된다는 보장만 된다면, "Encoding.Default" 인자가 가장 좋을 것 같네요.
[ BOM 제거 버전 ]
using System;
using System.IO;
using System.Text;
class MainClass
{
static void Main()
{
using (FileStream fs = new FileStream("test.txt", FileMode.Create))
{
using (StreamWriter w = new StreamWriter(fs, new UTF8Encoding(false)))
{
w.WriteLine(124.23M);
w.WriteLine("Test string");
w.WriteLine('!');
}
}
using (FileStream fs = new FileStream("test.txt", FileMode.Open))
{
using (StreamReader r = new StreamReader(fs, Encoding.UTF8, true))
{
Console.WriteLine(Decimal.Parse(r.ReadLine()));
Console.WriteLine(r.ReadLine());
Console.WriteLine(Char.Parse(r.ReadLine()));
}
}
}
}
'IT_Programming > C#' 카테고리의 다른 글
Closure in C# (0) | 2011.05.12 |
---|---|
비동기 방식의 콜백함수 (AsyncCallBack, BeginInvoke(), EndInvoke()) (0) | 2009.07.08 |
[펌] using / foreach와 try / catch 확장 (0) | 2008.12.18 |
[C++/CLI, C#] Predicate으로 사용할 객체형 대리자 및 무명 메서드. (0) | 2008.01.10 |
스레드(thread) 예제 (0) | 2007.12.23 |