인터넷에서 받은 CSV 파일을 엑셀로 열었더니 한글 이름과 주소가 씠由, 룄떆처럼 알 수 없는 글자나 네모(□) 기호로 바뀌어 본 적이 있을 것입니다. 숫자와 영어는 멀쩡한데 유독 한글만 깨집니다.
파일이 손상된 것이 아닙니다. 데이터는 그대로 들어 있고, 한글을 저장한 방식과 엑셀이 읽는 방식이 서로 어긋났을 뿐입니다. 왜 그런지 실제 바이트로 확인하고, 세 가지 방법으로 풀어 보겠습니다.

원인부터: 한글을 저장하는 방식이 둘이라서
컴퓨터는 글자를 숫자(바이트)로 바꿔 저장합니다. 한글을 저장하는 방식은 크게 두 가지가 쓰입니다. 하나는 윈도우가 오래전부터 쓰던 CP949(완성형, ANSI라고도 표기), 다른 하나는 오늘날 웹 표준인 UTF-8입니다.
문제는 윈도우용 엑셀이 확장자가 .csv인 파일을 더블클릭하면 내용을 시스템 기본 코드페이지(한국어 윈도우에서는 CP949)로 읽는다는 점입니다. 그래서 파일이 UTF-8로 저장돼 있으면, 엑셀은 그 바이트를 CP949 규칙으로 잘못 해석해 엉뚱한 글자를 보여 줍니다.
같은 파일을 구글 시트로 열면 멀쩡한데 엑셀에서만 깨지는 것도 이 때문입니다. 구글 시트는 CSV를 UTF-8로 먼저 읽으려 시도합니다. 파일이 아니라 읽는 프로그램의 기본값이 결과를 가릅니다.
같은 한글이라도 방식마다 차지하는 바이트 수가 다릅니다. 윈도우 11, 파이썬 3.12.10 표준 라이브러리로 직접 재 보았습니다.
| 글자 | CP949 | UTF-8 | UTF-8 (BOM 포함) |
|---|---|---|---|
| 가 | 2 byte | 3 byte | 6 byte |
| 한글 | 4 byte | 6 byte | 9 byte |
| 안녕하세요 | 10 byte | 15 byte | 18 byte |
한글 한 글자가 CP949에서는 2바이트, UTF-8에서는 3바이트입니다. 표현하는 숫자 자체가 다르니, 한쪽으로 저장한 것을 다른 쪽 규칙으로 읽으면 글자가 어긋날 수밖에 없습니다.
바이트로 보면 어긋남이 분명합니다
한글 '가'를 각 방식으로 저장했을 때 실제로 어떤 바이트가 적히는지 16진수로 꺼내 보았습니다.
CP949 : B0 A1 (2 byte)
UTF-8 : EA B0 80 (3 byte)
UTF-8(BOM) : EF BB BF EA B0 80 (6 byte)
맨 앞의 EF BB BF가 바로 BOM(Byte Order Mark)입니다. "이 파일은 UTF-8입니다"라고 알려 주는 표식으로, 엑셀은 이 표식을 보면 파일을 UTF-8로 읽습니다. 반대로 BOM이 없는 UTF-8 파일은 표식이 없어 엑셀이 CP949로 착각합니다.
실제로 이름,도시라는 글자를 BOM 없는 UTF-8로 저장한 뒤 CP949로 읽게 하면 결과는 이렇게 깨집니다.
원본(UTF-8 저장) : 이름,도시
CP949로 잘못 읽음 : 씠由,룄떆
UTF-8의 3바이트 한글을 CP949가 2바이트씩 끊어 읽으면서 전혀 다른 글자가 됩니다. 끊은 자리가 CP949에 없는 조합이면 네모(□)나 물음표로 보입니다. 글자가 깨졌다면 데이터가 망가진 것이 아니라 읽는 방식만 틀린 것입니다.
그래서 이미 깨져 보이는 화면 상태로 다시 저장하면 안 됩니다. 그 순간 잘못 읽힌 글자가 진짜 데이터로 굳습니다. 화면을 고치려 하지 말고 원본 파일을 올바른 방식으로 다시 여는 것이 먼저입니다.
이름을 읽는 규칙이 어긋나 글자가 깨지는 현상은 CSV만의 일이 아닙니다. 압축을 풀었더니 파일 이름이 깨져 있는 경우도 뿌리가 같습니다.
해결법 세 가지
읽는 쪽(엑셀)을 바꾸기보다 파일을 엑셀이 알아보게 저장하는 편이 간단합니다.
1. UTF-8(BOM 포함)으로 다시 저장하기. 가장 확실한 방법입니다. 파일 앞에 BOM 표식을 붙이면 엑셀이 UTF-8로 인식합니다. 파이썬에서는 인코딩 이름을 utf-8-sig로 지정하면 BOM이 자동으로 붙습니다. 저장하는 쪽 절차는 엑셀과 메모장과 파이썬에서 각각 UTF-8로 저장하는 법에 따로 정리해 두었습니다. 윈도우 엑셀로 열 일이 많다면 이쪽을 기본값으로 두면 됩니다.
import csv
rows = [["이름", "도시"], ["김민수", "서울"]]
with open("result.csv", "w", encoding="utf-8-sig", newline="") as f:
csv.writer(f).writerows(rows)
2. CP949(ANSI)로 저장하기. 받는 사람이 모두 한국어 윈도우 엑셀만 쓴다면 처음부터 CP949로 저장해도 깨지지 않습니다. 다만 다른 운영체제나 웹에서는 다시 깨질 수 있어 호환성은 UTF-8(BOM)이 더 넓습니다.
3. 엑셀에서 인코딩을 지정해 가져오기. 파일을 직접 고칠 수 없다면, 엑셀에서 더블클릭 대신 [데이터] 탭의 가져오기 기능으로 불러오면서 원본 인코딩을 65001(UTF-8)로 선택합니다. 메모장으로 열어 [다른 이름으로 저장]에서 인코딩을 바꿔 다시 저장하는 방법도 있습니다.
직접 확인하고 싶다면
아래 코드는 같은 내용을 BOM 없는 UTF-8과 UTF-8(BOM)으로 각각 저장합니다. 파이썬이 깔려 있다면 그대로 붙여 넣어 돌리면 됩니다. 두 파일을 엑셀로 열어 나란히 비교해 보면 차이가 바로 보입니다.
import csv
rows = [["이름", "도시"], ["김민수", "서울"], ["이서연", "부산"]]
# 깨지는 버전 (BOM 없음)
with open("no_bom.csv", "w", encoding="utf-8", newline="") as f:
csv.writer(f).writerows(rows)
# 정상 버전 (BOM 포함)
with open("with_bom.csv", "w", encoding="utf-8-sig", newline="") as f:
csv.writer(f).writerows(rows)
BOM을 붙이면 용량이 늘까 걱정할 필요는 없습니다. 위 데이터를 헤더 포함 101행으로 늘려 세 방식으로 저장해 봤습니다. BOM 없는 UTF-8이 1,815바이트, BOM 포함이 1,818바이트로 차이는 파일 앞 3바이트뿐입니다. 몇 행을 담든 BOM은 딱 한 번만 붙기 때문입니다.
같은 데이터를 CP949로 저장하면 1,311바이트가 됩니다. 한글 한 글자를 2바이트로 담으니 UTF-8보다 504바이트 작습니다. 용량만 보면 CP949가 유리해 보이지만, 그 대가로 한국어 윈도우 밖에서는 다시 깨집니다. 이 정도 차이 때문에 호환성을 버릴 이유는 없습니다.
위 결과는 한국어 윈도우 기준이며, 엑셀 버전과 설정에 따라 표시가 조금 다를 수 있습니다.
엑셀로 열 CSV라면 저장할 때 인코딩을 UTF-8(BOM 포함), 파이썬에서는 utf-8-sig로 지정해 두세요. 이 한 줄만 챙겨도 한글 깨짐의 대부분이 사라집니다.
'파일 형식 백과사전' 카테고리의 다른 글
| JSON 파일이 커서 안 열릴 때, 통째로 읽지 않고 훑어보는 법 (0) | 2026.09.26 |
|---|---|
| 사진을 열었다 저장할 때마다 나빠진다는 말, 어디까지 사실일까 (0) | 2026.09.25 |
| CSV를 열었더니 모든 값이 A열 한 칸에 몰려 있을 때 (0) | 2026.09.25 |
| 화면 캡처 PNG가 유독 무거울 때, 색 수를 줄여 절반으로 (0) | 2026.09.24 |
| 화면에서 쨍하던 초록이 인쇄물에서 칙칙해지는 이유 (0) | 2026.09.24 |