본문 바로가기

C

UTF-8 파일 읽을때 癤? 나오는경우 Byte Order Mark(BOM)

txt파일을 읽을때 파일 앞부분이 제대로 나오지 않는 경우가 있다.



다양한 언어를 표현할 수 있도록 해주는 유니코드(Unicode) 인코딩에는 여러가지 방식이 있습니다. 최근 웹 환경에서 많이 쓰이는 UTF-8을 비롯해서 UTF-16, UTF-32 등이 이런 인코딩 방식을 나타내지요.

이렇게 비슷한 방식을 사용하는 문서는 Byte Order Mark(BOM)로 구별이 됩니다. 문서 맨 앞에 눈에 보이지 않는 특정 바이트(byte)를 넣은 다음 이것을 해석해서 정확히 어떤 인코딩 방식이 사용되었는지 알아내는 방법이지요.

그런데 UTF-8 인코딩 방식에서는 BOM이 문제를 일으킬 수 있습니다. BOM이 무엇이고 왜 문제를 일으키는지, 그리고 어떻게 해결해야 하는지 알아보겠습니다.

BOM의 용도와 종류

BOM은 인코딩된 문서 첫 머리에 사용되어 정확한 인코딩 방식을 알려주는 역할을 하는데 대표적인 인코딩 방식과 그에 따른 BOM 목록은 아래 표와 같습니다.

인코딩 방식Byte Order Mark(BOM)
UTF-8EF BB BF
UTF-16 Big EndianFE FF
UTF-16 Little EndianFF FE
UTF-32 Big Endian00 00 FE FF
UTF-32 Little EndianFF FE 00 00

예를 들어서 문서 처음 2개의 바이트가 FE FF로 시작되면 그 문서는 UTF-16 Big Endian으로 해석되고, 반대로 FF FE로 시작되면 UTF-16 Little Endian으로 해석되는 것이지요.

그런데 UTF-8은 다른 인코딩 방식과는 다르게 BOM의 순서가 EF BB BF로 정해져 있습니다. 그래서 이 BOM은 바이트 순서와(Byte Order) 상관없기 때문에 UTF-8 Signature라고 불리지요. 즉, 해당 문서가 UTF-8로 인코딩되었다는 사실을 알리는 사인(signature)입니다.

UTF-8 BOM으로 생기는 문제

UTF-8은 인코딩 형식이 고정되어 있기 때문에 BOM이 없어도 인코딩 방식을 자동으로 알아낼 수 있습니다. 따라서 실제로는 BOM이 불필요하지요.

하지만 일부 윈도우즈 프로그램(메모장 같은)은 UTF-8 파일을 생성할 때 자동으로 BOM을 집어넣습니다. 윈도우즈 환경에서는 눈에 띄지 않는 경우가 많지만 리눅스(LINUX)나 유닉스(UNIX) 환경에서는 많은 문제를 일으키는 원인이 되지요.

대표적인 예로 PHP에서 include 구문을 사용할 때 생기는 여백(space)을 들 수 있습니다. 이것은 비단 BOM의 문제 뿐 아니라 웹 서버의 설정과도 관련이 있기 때문에 모든 경우에 생기는 문제는 아닙니다.

먼저 인터넷 익스플로러(이하 IE)에서 아래 두 링크를 열어보시기 바랍니다.

† 2010년 3월 20일: 아래 링크는 더 이상 유효하지 않습니다. ^^;

BOM이 있는 문서 인클루드BOM이 없는 문서 인클루드

두 문서는 이미지를 인클루드하는 부분을 제외하면 같은 소스를 사용합니다. 인클루드되는 파일 역시 BOM 유무를 빼면 동일합니다.

따라서 브라우저에서 두 문서의 소스를 확인해 보면 전혀 차이가 없습니다. 하지만 IE에서 두 페이지는 다르게 보입니다.

† 파이어폭스는 문서 내에 BOM이 들어가도 제대로 처리합니다. 따라서 두 링크가 동일하게 보이지요. 또한 웹 서버 환경에 따라서도 문제 발생 여부가 달라집니다. 동일한 파일을 다른 서버에 올릴 경우에는 문제가 안생길 수도 있으니까요.

UTF-8 BOM 문제의 원인

이렇게 두 문서가 다르게 보이는 이유는 눈에 보이지 않는 BOM 때문입니다. 사실 두 문서는 완전히 동일하지 않거든요. 단지 이 차이가 일반적인 환경에서는 보이지 않을 뿐입니다. 하지만 인클루드 되는 파일을 헥사 에디터((hex editor)로 열어보면 아래 이미지처럼 차이가 드러납니다.

BOM이 있는 파일의 헥사 코드

test1.html에서 인클루드한 BOM이 있는 파일입니다.

BOM이 없는 파일의 헥사 코드

test2.html에서 인클루드한 BOM 없는 파일입니다.

† 급조해서 만들다 보니 img 태그에 alt 속성이 빠졌군요. 접근성 향상을 위해서 꼭 넣어주는 것이 좋습니다. ^^;

첫 번째 이미지 맨 앞에 보이는 세 개의 바이트, EF BB BF가 test1.html에 들어가고, IE가 이 BOM을 제대로 해석하지 못하기 때문에 문제가 생기는 것이지요.

BOM 문제를 해결하는 방법

가장 좋은 방법은 BOM을 처음부터 넣지 않는 것입니다. 윈도우즈의 메모장 대신 BOM 설정이 가능한 전문적인 텍스트 에디터를 사용하는 것이 좋겠지요.

에디트플러스 BOM 설정

위 이미지는 텍스트 에디터로서 좋은 평가를 받고 있는 에디트플러스의 BOM 관련 옵션 설정 창입니다. UTF-8 Signature가 BOM을 가르키는데 선택 가능한 값과 그 의미는 아래와 같습니다.

  • Preserve existing signature: BOM이 있을 경우에만 그대로 유지합니다.
  • Always add signature: 항상 BOM을 넣습니다.
  • Always remove signature: BOM이 있으면 무조건 제거합니다.
  • Add signature if necessary: 필요할 경우에만 BOM을 넣습니다.

여기에서 ‘Always remove signature’로 지정하면 편집하는 모든 파일의 BOM이 제거됩니다. 다른 텍스트 에디터에도 비슷한 설정이 있는 경우가 많습니다. 예를 들어서 프리웨어 텍스트 에디터인 Notepad++는 옵션 설정 창의 ‘New Document’ 탭에서 인코딩 방식을 UTF-8 without BOM으로 설정하면 BOM이 없는 UTF-8 문서를 만들 수 있습니다.

마치며

지금껏 제 경험으로는 UTF-8 문서에서 BOM이 필요했던 경우는 없었습니다. 하지만 특정한 환경에서는 필요할 수도 있으니 상황에 따라 적절히 적용하는 것이 좋습니다.

여담이지만 처음 웹 표준을 접하고 홈페이지를 만들 때 웹 저작 툴인 마이크로 소프트의 익스프레션 웹 배타판을 사용했는데 CSS에서 * { margin: 0; padding: 0; }을 지정해도 여백이 생겨서 한참 헤맸었습니다. 알고보니 익스프레션 웹이 자동으로 넣은 BOM 때문이더군요.

출처 - http://blog.wystan.net/2007/08/18/bom-byte-order-mark-problem


해결방법


1. 파일을 읽은 뒤에 fseek로 파일 첫부분에서 3바이트만큼 앞으로 이동시킨다.

  FILE *ifp = fopen("before.txt", "rb");

int fileLineCount = 0;

while (!feof(ifp)){

if (fgetc(ifp) == '\n')

fileLineCount++;

}

fseek(ifp, 0, SEEK_SET);


2. 윈도우 txt 대신 다른 에디터를 이용한다.