포맷
고친 사람 github-actions[bot]
포맷은 한 낱말이 네 가지 일을 가리키는 말입니다. 데이터를 바이트로 적는 규칙일 때가 있습니다. 저장장치를 쓸 수 있게 준비하는 작업일 때도, 값이나 소스 코드의 모양을 틀에 맞추는 일일 때도 있습니다. 어느 세계의 이야기인지를 먼저 봐야 뜻이 정해집니다.
쉽고 빠른 이해
무슨 일을 가리키나 — 맥락마다 다릅니다. 「이 사진 파일은 어느 포맷인가」의 포맷은 데이터를 적는 규칙입니다. 「드라이브를 포맷했다」의 포맷은 저장장치에 파일 시스템을 새로 까는 작업입니다. 「값을 포맷해서 찍는다」의 포맷은 값을 글자로 바꾸는 틀입니다. 「코드를 포맷했다」의 포맷은 소스의 모양을 정해진 규칙으로 다시 맞추는 일입니다.
왜 따로 알아야 하나 — 뜻을 하나로만 알면 나머지 문장이 안 읽힙니다. 데이터 쪽 뜻만 아는 사람은 「드라이브를 포맷하면 데이터가 지워진다」에서 멈춥니다.
어떻게 가려 읽나
- 데이터나 파일을 두고 「무슨 포맷이냐」고 하면 적는 규칙입니다
- 드라이브나 디스크를 「포맷한다」고 하면 파일 시스템을 새로 까는 작업입니다
- 값이나 문자열을 「포맷한다」고 하면 글자로 찍는 틀입니다
- 소스 코드를 「포맷한다」고 하면 모양을 다시 맞추는 일입니다
대가 — 드라이브를 포맷하면 그 안의 데이터가 지워질 수 있습니다. 데이터 쪽에서는 버전이 갈리면 같은 이름 아래 규칙이 둘이 됩니다. 옛 파일을 계속 주고받으려면 변환기 같은 도구가 따라붙습니다.
상세
포맷이라는 낱말은 네 맥락에서 서로 다른 것을 가리킵니다. 데이터·파일 맥락에서는 데이터를 바이트로 적는 규칙입니다. 저장장치 맥락에서는 드라이브에 파일 시스템을 새로 만드는 작업입니다.
출력 맥락에서는 값을 사람이 읽을 문자열로 바꿔 찍는 틀입니다. 소스 코드 맥락에서는 프로그램 소스의 모양을 정해진 규칙으로 다시 맞추는 일입니다. 넷 다 그 세계에서 맞는 뜻이고, 어느 하나가 원래 뜻이라고 적은 자료는 없습니다.
같은 낱말이 문장 안에서 하는 일도 갈립니다. 「JSON(JavaScript Object Notation, 자바스크립트 객체 표기법)은 텍스트 포맷입니다」의 포맷은 규칙을 가리키는 명사입니다. 「드라이브를 포맷합니다」의 포맷은 작업을 가리키는 동사입니다. 「값을 포맷합니다」도 동사지만 목적어가 드라이브가 아니라 찍어 낼 값입니다.
다만 명사면 규칙, 동사면 작업이라고 가를 수는 없습니다. 아래 「저장장치를 쓸 수 있게 만드는 작업」에서 보듯 저장장치 맥락에서도 포맷을 명사로 씁니다.
데이터를 바이트로 적는 규칙
데이터 포맷은 정보를 파일로 저장하거나 네트워크로 흘려보낼 수 있게 바이트로 적는 방법을 정합니다. 바이트를 차례로 늘어놓은 흐름이 바이트 스트림입니다. 포맷은 머릿속의 정보 모델을 바이트 스트림으로 옮기는 규칙입니다.
메모리 안의 데이터를 이 규칙대로 바이트로 바꾸는 일이 직렬화입니다. JSON 은 구조가 있는 데이터를 직렬화하는 텍스트 포맷입니다. 받은 바이트를 같은 규칙으로 읽어 데이터로 되돌리는 일은 역직렬화입니다.
규칙이 있어야 하는 까닭은 적는 쪽과 읽는 쪽이 대개 서로 모르는 프로그램이기 때문입니다. 포맷을 적은 공개 문서가 충분히 자세하면, 따로 만든 두 구현이 그 문서만 보고도 같은 데이터를 주고받을 수 있습니다. 따로 만들어진 시스템이 이렇게 맞물려 도는 성질이 상호운용성입니다.
데이터 포맷이 정하는 세 층
데이터 포맷 하나를 뜯어보면 정해야 할 것을 세 층으로 나눠 볼 수 있습니다. 위층이 정해져도 아래층이 안 정해지면 바이트가 안 나옵니다.
flowchart TD
subgraph L1["1층 · 어떤 값이 올 수 있나"]
A["문자열 · 수 · 참거짓 · null · 객체 · 배열"]
end
subgraph L2["2층 · 값을 어떻게 묶고 늘어놓나"]
B["이름과 값의 짝 · 순서 있는 목록 · 덩어리의 순서"]
end
subgraph L3["3층 · 값 하나를 어떤 비트로 옮기나"]
C["문자 인코딩 · 부동소수점 표준"]
end
L1 --> L2
L2 --> L3
L3 --> D["파일에 쓸 바이트"]
첫째 층은 어떤 종류의 값이 올 수 있느냐입니다. JSON 은 기본 타입 넷과 구조 타입 둘을 담습니다. 기본 타입은 문자열·수·참거짓·null 입니다. 구조 타입은 객체와 배열입니다.
둘째 층은 값들을 어떻게 묶고 늘어놓느냐입니다. JSON 의 객체는 이름과 값의 짝을 순서 없이 모은 것입니다. 배열은 값을 순서대로 늘어놓은 것입니다.
문자가 아닌 바이트로 적는 포맷도 이 층을 정합니다. PNG(Portable Network Graphics) 이미지는 맨 앞에 시그니처라는 고정된 바이트 값을 둡니다. 그 뒤에는 청크라는 덩어리를 차례로 이어 붙입니다.
첫 청크는 이미지의 머리 정보를 담는 청크여야 합니다. 마지막 청크는 끝을 알리는 청크여야 합니다.
셋째 층은 값 하나를 실제 비트로 옮기는 일입니다. 파일 포맷 밑에 따로 깔린 인코딩이 이 층을 맡는 포맷도 있습니다. 문자는 UTF-8 같은 문자 인코딩이, 실수는 IEEE(Institute of Electrical and Electronics Engineers, 전기전자기술자협회) 754 같은 부동소수점 표준이 비트로 옮깁니다.
세 층 가운데 하나라도 적는 쪽과 읽는 쪽이 다르게 알고 있으면 읽는 쪽은 엉뚱한 값을 얻습니다. 바이트 자체는 자기를 어떤 규칙으로 읽어야 하는지 말해 주지 않기 때문입니다.
텍스트 포맷과 이진 포맷
데이터 포맷은 값을 사람이 읽는 문자로 적느냐, 그렇지 않느냐로 크게 둘로 갈립니다. 앞쪽이 텍스트 포맷, 뒤쪽이 이진 포맷입니다.
JSON 은 텍스트 포맷입니다. JSON 의 설계 목표는 넷이었습니다. 작을 것, 옮기기 쉬울 것, 문자로 적힐 것, 자바스크립트 문법의 부분집합일 것입니다. 텍스트로 적은 표현은 대개 그것을 해석하는 프로그램이 없어도 어느 정도 읽힙니다.
이미지나 오디오를 담는 이진 포맷은 다릅니다. 해석하는 프로그램 없이 열면 읽을 수 없는 바이트가 나옵니다. PNG 가 그런 포맷입니다.
| 텍스트 포맷 | 이진 포맷 | |
|---|---|---|
| 값을 적는 법 | 사람이 읽는 문자로 | 문자로 바꾸지 않은 바이트로 |
| 해석 프로그램 없이 열면 | 어느 정도 읽힌다 | 읽을 수 없다 |
| 예 | JSON | PNG 이미지 |
파일이 어느 포맷인지 알리는 표지
바이트만 봐서는 그것이 어느 규칙으로 적힌 것인지 알기 어렵습니다. 그래서 포맷을 알리는 표지를 따로 둡니다. 실무에서 자주 마주치는 표지는 아래 셋입니다. PNG 하나가 셋을 다 갖습니다.
| 표지 | 어디에 붙나 | PNG 의 값 |
|---|---|---|
| 파일 확장자 | 파일 이름 끝 | .png |
| 매직 넘버 | 파일 맨 앞의 고정된 바이트 | 89 50 4E 47 0D 0A 1A 0A |
| 미디어 타입 | 데이터와 함께 보내는 이름표 | image/png |
표지가 이 셋뿐인 것은 아닙니다. PNG 명세의 미디어 타입 등록 항목에는 매킨토시 파일 종류 코드 PNGf 도 함께 적혀 있습니다.
매직 넘버는 포맷마다 정해 둔 바이트 값을 파일 맨 앞에 박아 두는 방법입니다. PNG 데이터의 첫 8바이트는 언제나 위 값입니다. 이 값으로 PNG 를 다른 종류의 데이터와 가릅니다. 전송 중에 생긴 오류 가운데 일부도 이 값에서 일찍 잡힙니다.
PNG 데이터를 읽는 쪽은 이 표지부터 밟아 갑니다. 먼저 시그니처 8바이트로 PNG 인지 확인합니다. 다음에 머리 정보 청크를 읽습니다.
이미지 데이터 청크는 하나 이상 옵니다. 끝을 알리는 청크가 마지막입니다.
flowchart TD A["시그니처 8바이트<br/>PNG 인지 확인한다"] --> B["머리 정보 청크<br/>반드시 맨 처음"] B --> C["이미지 데이터 청크<br/>하나 이상"] C --> D["끝을 알리는 청크<br/>반드시 맨 마지막"]
미디어 타입은 데이터에 붙이는 포맷의 이름표입니다. MIME 타입이라고도 합니다. MIME(Multipurpose Internet Mail Extensions, 다목적 인터넷 메일 확장)은 전자우편에 갖가지 내용을 실어 나르는 규약입니다. MIME 은 이 이름표를 붙여 내용을 가립니다.
이름표는 image/png 처럼 상위 타입과 하위 타입으로 이뤄집니다. image 아래의 하위 타입이 구체적인 이미지 포맷의 이름입니다. audio 아래의 하위 타입은 구체적인 오디오 포맷의 이름입니다.
웹에서는 이 이름표를 HTTP(HyperText Transfer Protocol) 메시지에 실어 보냅니다. 메시지 본문 앞에 붙여 보내는 부가 정보 칸이 헤더입니다. 미디어 타입은 그 가운데 Content-Type 헤더에 들어갑니다. 이 이름표가 데이터 포맷과 받는 쪽의 처리 방법을 함께 정합니다.
보내는 쪽이 이름표를 빠뜨리면 받는 쪽이 고를 길은 둘입니다. 하나는 아무 바이트 덩어리(application/octet-stream)로 치는 것입니다. 다른 하나는 데이터를 직접 들여다봐 종류를 짐작하는 것입니다.
들여다보는 데에는 한계가 있습니다. 미디어 타입은 포맷만 정하지 않고 받는 쪽이 그 데이터를 어떻게 다룰지까지 정합니다. 그래서 서로 다른 미디어 타입이 같은 데이터 포맷을 쓰고 처리 방법만 다른 일이 흔합니다. 포맷이 같으면 바이트도 같으니 이 차이는 데이터만 봐서는 가려낼 수 없습니다.
포맷의 버전
데이터 포맷은 시간이 지나며 버전이 바뀝니다. 이미지 포맷 TIFF(Tagged Image File Format)는 Aldus 의 5.0 판이 Adobe 의 6.0 판으로 대체됐습니다. 미 의회도서관의 디지털 포맷 목록은 이렇게 시간을 두고 갈라진 버전들을 모두 포맷으로 셉니다.
버전이라는 말이 포맷이 아니라 제품에 붙는 일도 있습니다. Microsoft Office 는 .docx·.xlsx·.pptx 같은 XML(Extensible Markup Language) 기반 파일 형식을 씁니다. 그러면서도 예전 버전 Office 가 쓰던 이진 파일 형식으로 저장하는 길을 함께 둡니다. 버전이 다른 Office 끼리 파일을 주고받도록 호환성 검사기와 파일 변환기도 넣어 두었습니다.
이때 두 형식은 같은 이름의 두 버전이 아니라 서로 다른 포맷입니다. 그래도 한쪽을 버리지 않고 둘 다 쓸 수 있게 둔 결과는 같습니다. 옛 파일을 계속 주고받으려면 변환기 같은 도구가 따라붙습니다.
맥락별 뜻
맥락마다 뜻과 그 뜻을 적은 출처를 나란히 둡니다. 출처 칸의 RFC(Request for Comments)는 인터넷 표준을 담은 문서 묶음입니다. ISO(International Organization for Standardization)는 국제표준화기구입니다.
| 맥락 | 뜻 | 출처 |
|---|---|---|
| 데이터·파일 | 정보를 파일이나 바이트 스트림으로 담기 위해 바이트로 적는 규칙. 명사로 쓴다 | Library of Congress, Sustainability of Digital Formats · RFC 6838 §4 |
| 저장장치 | 드라이브에 새 루트 디렉터리와 파일 시스템을 만들어 파일을 받을 수 있게 하는 작업. 같은 설명에서 「디스크의 기본 포맷」처럼 명사로도 쓴다 | Microsoft Learn, format 명령 |
| 출력 서식 | 뒤따르는 값을 어떤 문자열로 바꿔 찍을지 정하는 틀. 서식 문자열이라고 한다 | Python 문서, Format string syntax · ISO C 초안 N1570 §7.21.6.1 |
| 소스 코드 서식 | 프로그램 소스의 들여쓰기와 정렬을 정해진 규칙으로 다시 맞추는 일 | Go 문서, gofmt 명령 |
저장장치를 쓸 수 있게 만드는 작업
Windows 의 format 명령은 드라이브가 Windows 파일을 받을 수 있게 포맷합니다. 디스크에 새 루트 디렉터리와 파일 시스템을 만드는 작업입니다. 루트 디렉터리는 모든 폴더의 맨 꼭대기 폴더입니다. 새 디스크를 쓰려면 먼저 이 명령으로 포맷해야 합니다.
이 작업 중에 디스크의 불량 영역을 검사할 수 있습니다. 디스크의 데이터를 모두 지울 수도 있습니다.
명령이 대상으로 받는 것은 볼륨입니다. 볼륨은 드라이브 안에서 파일 시스템 하나가 깔리는 구역입니다. 어떤 파일 시스템을 깔지는 /FS 옵션으로 고릅니다. FAT·FAT32·NTFS(New Technology File System)·exFAT·ReFS·UDF 가 여기 들어갑니다.
옵션을 안 주면 명령은 볼륨 종류를 보고 그 디스크의 기본 포맷을 정합니다. 이 「기본 포맷」의 포맷은 동사가 아니라 명사입니다. /FS 로 고르는 파일 시스템 종류를 가리키는 것으로 읽힙니다. 같은 설명 안에서 포맷이 동사와 명사로 함께 쓰입니다.
리눅스에서 같은 일을 하는 mkfs 명령의 설명에는 포맷이라는 낱말이 없습니다. mkfs 는 장치 위에 리눅스 파일 시스템을 짓는다고 적습니다. 그 장치는 대개 하드 디스크를 나눈 구역인 파티션입니다. 같은 작업을 Windows 는 포맷한다고, 리눅스는 파일 시스템을 짓는다고 부릅니다.
값을 문자열로 찍는 틀
출력 맥락의 포맷은 값을 사람이 읽을 문자열로 바꾸는 방법을 정합니다. 그 방법을 적어 둔 문자열이 서식 문자열(format string)입니다.
C 언어의 fprintf 함수는 서식 문자열을 하나 받습니다. 뒤따르는 인자들을 출력용으로 어떻게 바꿀지 정하는 것은 그 문자열입니다. 서식 문자열 안의 보통 문자는 바꾸지 않고 출력으로 옮깁니다. % 로 시작하는 변환 지정은 뒤따르는 인자를 필요한 만큼 가져와, 필요하면 바꿔서 출력에 씁니다.
인자가 서식이 요구하는 것보다 모자라면 동작이 정의되지 않습니다. 서식이 먼저 끝나고 인자가 남으면 남은 인자는 평가만 되고 쓰이지 않습니다.
파이썬의 서식 문자열은 중괄호 {} 로 둘러싼 치환 필드를 씁니다. 중괄호 밖의 글자는 바꾸지 않고 출력으로 옮깁니다. 치환 필드 안에서 콜론 : 뒤에 붙는 서식 지정이 그 값을 기본값이 아닌 모양으로 찍게 합니다.
소스 코드를 다시 맞추는 일
프로그램 소스를 정해진 모양으로 다시 맞추는 일도 포맷입니다. Go 언어의 gofmt 명령이 그런 일을 합니다. 들여쓰기에는 탭을, 정렬에는 공백을 씁니다. 정렬은 편집기가 고정폭 글꼴을 쓴다고 보고 맞춥니다.
한국어 옮김에서 갈리는 낱말
영어 format 하나가 한국어 문서에서는 포맷·서식·형식 셋으로 옮겨집니다. 한 문서 안에서도 갈립니다.
| 영어 | 한국어 옮김 | 어디서 |
|---|---|---|
| formats a drive | 드라이브를 포맷합니다 | Windows format 명령 한국어 설명 |
| formatting process | 서식 지정 프로세스 | 같은 문서 |
| the default format for the disk | 디스크의 기본 형식 | 같은 문서 |
| file formats | 파일 형식 | Microsoft Office 의 파일 형식 안내 |
| format strings | 포맷 문자열 | 파이썬 한국어 문서 |
그래서 한국어 문서의 「서식」이나 「형식」 뒤에 영어 format 이 있을 수 있습니다. Windows format 명령의 한국어 설명에 나오는 「서식 지정 프로세스」는 드라이브를 포맷하는 과정입니다.
경계
UTF-8 은 데이터·파일 맥락의 포맷인가. 이름만 보면 그렇게 읽힙니다. UTF-8 을 정의하는 인터넷 표준 RFC 3629 의 제목이 「ISO 10646 의 변환 포맷」입니다. UTF(Unicode Transformation Format)라는 줄임말도 변환 포맷을 뜻합니다.
아닙니다. UTF-8 은 데이터 포맷 아래에 깔리는 문자 인코딩입니다. 유니코드는 세계의 문자마다 번호를 매기는 표준입니다. 그 표준 안에서 UTF-8 은 인코딩 형식(encoding form)입니다.
인코딩 형식은 문자 하나에 매긴 번호를 인코딩 단위의 열로 옮기는 대응 규칙입니다. 인코딩 단위는 그 형식이 쓰는 기본 조각입니다. UTF-8 의 단위는 1바이트입니다. 그래서 UTF-8 은 번호 하나를 1~4바이트짜리 바이트 열 하나로 옮깁니다.
인코딩 방식(encoding scheme)은 한 걸음 더 간 규칙입니다. 인코딩 형식이 만든 단위를 바이트 순서까지 정해 늘어놓는 것을 정합니다. UTF-16 처럼 단위가 1바이트보다 큰 형식에서는 그 순서를 정해야 바이트 열이 하나로 정해집니다. UTF-8 은 단위가 이미 1바이트라 둘 사이에 할 일이 거의 없습니다.
flowchart TD A["문자"] --> B["문자 번호<br/>U+4E8C"] B --> C["인코딩 형식<br/>번호를 단위의 열로"] C --> D["인코딩 단위의 열<br/>UTF-8 의 단위는 1바이트"] D --> E["인코딩 방식<br/>단위를 늘어놓는 바이트 순서까지"] E --> F["바이트 열<br/>E4 BA 8C"]
대응은 이런 모양입니다. U+ 뒤의 16진수가 문자 번호입니다.
| 문자 번호 | UTF-8 바이트 열 |
|---|---|
| U+004D | 4D |
| U+0430 | D0 B0 |
| U+4E8C | E4 BA 8C |
| U+10302 | F0 90 8C 82 |
UTF-8 이 정하는 것은 문자 하나를 바이트로 옮기는 방법까지입니다. 앞 「상세」의 세 층으로 보면 셋째 층입니다.
근거는 둘입니다.
- 「변환 포맷」은 역사적 사정으로 남은 이름입니다. 유니코드 표준도 이 이름이 인코딩 형식을 가리키는지 인코딩 방식을 가리키는지 모호하다고 적습니다
- 미 의회도서관의 디지털 포맷 목록은 포맷이라는 말을 아주 넓게 써서 UTF-8 도 포맷 범위에 넣습니다. 다만 파일 포맷 밑에 깔리는 비트열 인코딩이라는 갈래로 따로 넣습니다
여담
빠른 포맷은 디스크 전체를 0 으로 덮지 않습니다. Microsoft 의 format 명령 설명에 따르면 빠른 포맷(/Q)은 이미 포맷된 볼륨에서 파일이 어디 있는지 적은 파일 테이블과 루트 디렉터리를 지웁니다. 불량 영역을 찾는 섹터 단위 검사는 건너뜁니다.
섹터는 디스크를 읽고 쓰는 가장 작은 조각입니다. 파일 테이블은 그 조각들 가운데 어디에 어느 파일이 있는지 적어 둔 표입니다.
Microsoft 지원 문서 KB(Knowledge Base) 941961 에 따르면 전체 포맷이 기본으로 디스크 전체에 0 을 쓰게 된 것은 Windows Vista 부터입니다. 그보다 앞선 Windows 에서는 전체 포맷도 디스크 전체에 0 을 쓰지 않았습니다. 섹터마다 0 을 쓴 뒤 난수로 몇 번 더 덮어쓰게 하는 /P 옵션도 있습니다. /Q 와 함께 주면 이 옵션은 무시됩니다.
관련 항목
포맷이 바이트를 쪼개는 방법
구분자 · 고정 길이 필드 · 가변 길이 필드 · 엔디언 · 옥텟 · 패딩 · 청크 · 바이트 스트림
파일이 어느 포맷인지 알려 주는 표지
파일 확장자 · 매직 넘버 · 파일 시그니처 · MIME · 미디어 타입 · Content-Type · MIME 스니핑 · application/octet-stream
포맷 밑에서 문자를 바이트로 옮기는 인코딩
문자 인코딩 · 문자 집합 · UTF-8 · UTF-16 · ASCII · EUC-KR · 바이트 순서 표시 · 인코딩 형식 · 인코딩 방식 · 코드 유닛 · IEEE 754
텍스트로 적는 데이터 포맷
JSON · XML · YAML · CSV · TOML · INI 파일
바이트로 적는 데이터 포맷
Protobuf · PNG · TIFF · 클래스 파일 · 실행 파일 · JAR · SPIR-V · TZif
데이터를 포맷으로 바꾸고 되돌리는 작업
직렬화 · 역직렬화 · 파서 · 파싱 · 압축 · Base64
포맷이 지켜야 하는 약속
하위 호환 · 상호운용성 · 스키마 · 스키마 진화 · 명세 · 표준
포맷과 맞세워지는 대립 개념
프로토콜 · 인터페이스 · API · 계약 · 중간 표현
저장장치를 포맷할 때 다루는 구조
디스크 포맷 · 파일 시스템 · 빠른 포맷 · 볼륨 · 파티션 · 섹터 · 불량 섹터 · 루트 디렉터리 · NTFS · FAT32 · exFAT · mkfs
값을 문자열로 포맷하는 도구
서식 문자열 · 출력 서식 · printf · 치환 필드 · 변환 지정자 · f-string · gofmt · 코드 포매터
다른 이름: format · data format · file format · 데이터 포맷 · 파일 포맷 · formatting · 포맷팅