파이썬 JSON 한글 저장: UTF-8 BOM과 utf-8-sig 구분법

새 JSON 파일은 BOM 없는 UTF-8로 저장하고, 기존 파일에서 BOM이 확인될 때만 utf-8-sig로 읽는 것이 기본 판단입니다. 한글이 보이지 않는다는 이유만으로 두 설정을 같은 문제의 해결책처럼 바꾸면, 저장 형식과 읽기 호환성 문제를 놓치기 쉽습니다. 먼저 파일 시작 부분의 BOM 여부를 확인한 뒤 저장과 읽기에 서로 다른 선택을 적용하면 됩니다.

BOM 오류와 한글 깨짐은 먼저 나눠 보세요

JSON을 열었을 때 첫 글자 부근에서 오류가 난다면 파일 맨 앞에 UTF-8 BOM이 붙었는지 확인할 만합니다. Python의 JSON 디코더는 입력 시작의 BOM을 허용하지 않아 ValueError를 일으킬 수 있습니다. 반면 한글이 \u 형태로 보이는 현상은 JSON 직렬화 표기와 관련된 문제일 수 있어, BOM과 같은 원인으로 단정하면 안 됩니다.

운영에서 저는 다음 순서로 범위를 좁힙니다.

  1. 파일을 만든 프로그램이나 편집기에서 UTF-8 BOM 저장 옵션을 확인합니다.
  2. 파일을 바이너리로 열어 시작 바이트가 EF BB BF인지 확인합니다.
  3. BOM이 있으면 읽기 단계에서만 utf-8-sig를 검토합니다.
  4. 새로 저장하는 파일은 BOM 없는 utf-8을 우선합니다.

utf-8과 utf-8-sig의 역할은 다릅니다

UTF-8은 바이트 순서 문제를 해결하기 위해 BOM이 필요한 인코딩이 아닙니다. utf-8-sig는 이름처럼 UTF-8 BOM을 다루는 변형입니다. 디코딩할 때 파일 시작의 BOM을 건너뛰고, 인코딩할 때는 UTF-8 BOM 바이트 EF BB BF를 앞에 붙입니다.

따라서 두 인코딩은 이렇게 구분하면 실수가 줄어듭니다.

상황 선택 이유
새 JSON을 저장 utf-8 불필요한 BOM을 만들지 않음
BOM이 있는 기존 JSON을 읽음 utf-8-sig 시작 BOM을 건너뜀
BOM이 없는 일반 UTF-8을 읽음 utf-8 원래 인코딩을 그대로 해석함

utf-8-sig를 모든 파일의 기본값으로 쓰기보다는, 외부 도구가 만든 기존 파일과의 호환성이 확인될 때 제한적으로 사용하는 편이 파일 형식을 예측하기 쉽습니다.

Python에서 저장과 읽기를 나눠 작성하기

새 파일을 저장하는 코드는 encoding="utf-8"을 명시하면 의도가 분명합니다.

import json

data = {"message": "한글 JSON"}

with open("data.json", "w", encoding="utf-8") as file:
    json.dump(data, file, ensure_ascii=False, indent=2)

기존 파일에 BOM이 있다는 것이 확인된 경우에는 읽기 단계에서만 utf-8-sig를 사용합니다.

import json

with open("legacy-data.json", "r", encoding="utf-8-sig") as file:
    data = json.load(file)

여기서 ensure_ascii=False는 한글을 JSON 문자열에 그대로 표시하기 위한 직렬화 옵션입니다. 파일의 UTF-8 BOM을 제거하거나 추가하는 인코딩 선택과는 별개입니다. 기본값인 ensure_ascii=True는 비ASCII 문자를 이스케이프할 뿐, 파일 인코딩 문제를 해결하는 설정은 아닙니다.

새 파일을 만들 때의 판단 기준

새로운 자동화 작업에서 JSON 파일을 만든다면 utf-8 저장을 기본으로 정합니다. Python 공식 문서도 JSON 상호운용성에서 UTF-8을 권장하고, JSON 시작 부분의 BOM은 허용하지 않는다고 설명합니다. Python의 JSON serializer는 BOM을 추가하지 않습니다.

이미 전달받은 파일을 읽는 경우에는 파일의 실제 형식을 존중해야 합니다. 오류가 난다는 이유만으로 utf-8-sig를 붙이기보다, 파일의 시작 바이트와 생성 도구의 저장 옵션을 확인하세요. BOM이 없다면 일반 UTF-8로 읽고, BOM이 있다면 utf-8-sig로 읽는 식입니다.

이 판단으로도 문제가 남으면 다음 질문을 별도로 확인해야 합니다.

  • ensure_ascii=False와 파일 인코딩은 어떻게 구분하나요?
  • JSON 저장 후 Python에서 읽기까지 왕복 검증하려면 어떻게 하나요?

공식 문서

Leave a Comment