1. 기본 인코딩
StreamReader나 StreamWriter로 작업할 때, 이들은 기본 인코딩을 사용합니다.
만약 이렇게 작성하면:
using var reader = new StreamReader("myfile.txt");
또는
using var writer = new StreamWriter("output.txt");
.NET은 기본 인코딩을 선택합니다. Windows에서는 보통 UTF-8(종종 BOM 없음)이지만, 오래된 앱이나 다른 시스템에서는 동작이 다를 수 있어요.
대부분의 경우 UTF-8이 좋은 선택입니다: 모든 언어를 지원하고 영어 텍스트(러시아어도 포함)에 대해 저장이 효율적이에요. 하지만 파일이 다른 인코딩(예: Windows-1251)으로 만들어졌거나, 특정 인코딩을 기대하는 다른 프로그램에서 파일을 읽을 경우에는 명시적으로 인코딩을 지정해야 합니다.
2. StreamReader와 StreamWriter에 인코딩 지정하기
생성자 옵션들
StreamReader와 StreamWriter 모두 System.Text.Encoding 타입의 객체를 전달할 수 있는 생성자를 지원합니다.
예:
using var reader = new StreamReader("myfile.txt", Encoding.UTF8);
using var writer = new StreamWriter("output.txt", false, Encoding.UTF8);
만약 ASCII, Windows-1251 또는 UTF-16로 작업하고 싶다면, 다른 인코딩을 넣어주면 됩니다:
using var reader = new StreamReader("myfile.txt", Encoding.Unicode); // UTF-16
using var reader2 = new StreamReader("rus.txt", Encoding.GetEncoding("windows-1251"));
자주 쓰이는 인코딩 간단 표:
| 인코딩 | C# 표현식 | 설명 |
|---|---|---|
| UTF-8 | |
모든 언어 지원, 용량 효율적 |
| UTF-16 (Unicode) | |
.NET 표준, 문자당 2바이트 |
| ASCII | |
기본 문자(영어)만 |
| Windows-1251 | |
러시아어, 오래된 Windows 프로그램용 |
주의! Windows-1251 같은 비표준 인코딩을 쓸 때는 Encoding.GetEncoding("windows-1251")를 사용하세요.
3. 인코딩을 명시해서 읽고 쓰기
작은 미니 앱에 기능 하나를 추가해봅시다: 지정한 인코딩으로 파일을 읽고, 결과를 다른 파일에 명시적으로 지정한 인코딩으로 쓰는 기능이에요. 이렇게 하면 시스템 간 텍스트 변환이 가능합니다.
예 1: Windows-1251 인코딩 파일을 읽어서 화면에 출력하기
// 예: 파일이 오래된 Windows-1251로 생성되었다고 가정
using var reader = new StreamReader("ru_text.txt", Encoding.GetEncoding("windows-1251"));
string line;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
}
왜 중요한가: 인코딩을 지정하지 않으면 러시아어 문자 대신 끔찍한 기호들(예: "Учебник")이 나올 수 있습니다.
예 2: UTF-16 (Unicode)로 파일 쓰기
using var writer = new StreamWriter("utf16text.txt", false, Encoding.Unicode);
writer.WriteLine("안녕, 세상!");
writer.WriteLine("Hello, world!");
writer.WriteLine("こんにちは世界");
결과: 예를 들어 Notepad로 파일을 열어보면 모든 문자가 제대로 표시됩니다.
4. 인코딩 변환용 작은 유틸리티
자주 묻는 과제(면접에서 자주 나옵니다!): 텍스트 파일을 Windows-1251에서 UTF-8로 변환하라.
string sourcePath = "ru_text_1251.txt";
string destPath = "ru_text_utf8.txt";
// Windows-1251 인코딩으로 읽기
using var reader = new StreamReader(sourcePath, Encoding.GetEncoding("windows-1251"));
// UTF-8로 쓰기
using var writer = new StreamWriter(destPath, false, Encoding.UTF8);
string? line;
while ((line = reader.ReadLine()) != null)
writer.WriteLine(line);
이제 ru_text_utf8.txt는 VSCode, Linux, Mac 등에서 문제없이 열어 읽을 수 있습니다.
5. 유용한 팁
파일이 어떤 인코딩인지 어떻게 알까?
꽤 까다로운 문제입니다! 대부분의 파일은 내부에 인코딩 정보를 저장하지 않습니다(예외로 BOM이 있는 파일이 있긴 해요 — 이건 다음 강의에서 더 자세히 다룹니다). 잘못된 인코딩으로 열면 결과는 그냥 깨진 텍스트가 됩니다.
실무에서 흔히 쓰는 접근법:
- 파일을 당신이 만든 프로그램이 생성했다면 — 쓰기 때 사용한 동일한 인코딩으로 읽어라.
- 출처가 불명확한 파일이라면 — 여러 인코딩을 시도해보거나 전용 유틸리티로 인코딩을 검사해라.
이모지와 특이한 문자 다루기
UTF-8과 UTF-16은 이모지와 여러 언어의 문자를 자유롭게 사용할 수 있게 해줍니다. 이모지를 포함한 파일을 UTF-8로 저장한 뒤 오래된 단일 바이트 인코딩으로 열어보면 재밌는(또는 골치 아픈) 결과를 볼 수 있어요.
이모지 예제:
using var writer = new StreamWriter("emoji.txt", false, Encoding.UTF8);
writer.WriteLine("안녕 👋😀🌍");
StreamReader의 인코딩 자동 감지
StreamReader 생성자에는 detectEncodingFromByteOrderMarks 파라미터를 받는 오버로드가 있습니다:
new StreamReader(path, encoding, detectEncodingFromByteOrderMarks: true)
이 파라미터가 true이면(기본값입니다!), StreamReader는 파일 시작에 있는 BOM을 보고 인코딩을 추측하려 시도합니다. 다만 파일이 BOM 없이 만들어졌거나 진기한 인코딩을 쓴 경우에는 이 자동 감지가 실패할 수 있습니다.
언제/왜 명시적으로 인코딩을 지정해야 할까?
- 다국어 데이터: 아랍어, 중국어, 이모지 등 다양한 문자를 지원해야 할 때.
- 통합(Integration): 파일을 여러분 프로그램뿐 아니라 다른 시스템도 읽고 쓴다면, 상대가 기대하는 인코딩을 맞춰줘야 합니다.
- 파일 크기 중요: 라틴 계열 텍스트는 ASCII/UTF-8가 더 공간 효율적이고, 한자 같은 경우는 UTF-16이 유리할 수 있습니다.
- 호환성: 로그나 내보내기 파일을 다른 애플리케이션과 공유할 때.
6. 인코딩 작업에서 흔한 실수들
실수 #1: 파일을 읽을 때 인코딩을 명시하지 않음.
러시아어나 다른 비라틴 문자가 들어있는 파일을 인코딩 없이 읽으면 보통 읽을 수 없는 '깨진 문자열'이 나옵니다.
실수 #2: 쓰기와 읽기의 인코딩 불일치.
파일을 한 인코딩으로 썼는데 다른 인코딩으로 열면 텍스트가 왜곡됩니다. OS나 프로그램 간 이동할 때 자주 발생합니다.
실수 #3: 지원하지 않거나 부분적으로만 지원되는 인코딩 사용.
어떤 편집기는 BOM 없는 UTF-8을 제대로 못 보거나, 오래된 단일 바이트 인코딩(예: Windows-1251)을 제대로 처리하지 못할 때가 있습니다. 이럴 땐 수동으로 인코딩을 바꿔보고 실험해야 합니다.
GO TO FULL VERSION