ByteScope

テキスト(UTF-8 BOM)ファイル形式

バイトオーダーマーク付きの UTF-8 でエンコードされたプレーンテキスト。

MIME タイプ
text/plain
拡張子
.txt
カテゴリ
テキスト・マークアップ

マジックナンバー(ファイル署名)

0x00000000EFBBBF···UTF-8 BOM

テキスト(UTF-8 BOM)形式について

バイトオーダーマークとは、ファイルの一番先頭に置かれた U+FEFF という文字のことです。UTF-16 では名前どおりの働きをします。FF FE と FE FF は区別できて、読む側もどちら向きなのかを本当に知る必要があるからです。ところが UTF-8 には印を付けるべきバイト順がありません。EF BB BF の 3 バイトは「このファイルは UTF-8 である」と示すためだけに存在し、Unicode の標準はこれを要求も推奨もしていません。それでも Windows のエディタが付けるのは、付けなければ Windows ではシステムのコードページとして読まれてしまうからでした。その結果生まれたのが、Windows と Unix のツール群のあいだにある、決着を試みるたびに生き延びてきた低レベルの摩擦です。

ヘッダーの構造(バイト単位)

オフセット長さフィールド意味
03UTF-8 byte-order markEF BB BF、U+FEFF を UTF-8 で符号化したもので、この文字の Unicode 上の名前は zero width no-break space です。この前には何も置けません。オフセット 0 に無い BOM はもはや BOM ではなく、テキストの途中に居座る見えない文字にすぎません。
01Lead byte EF2 進では 1110 1111。上位 3 ビットが 3 バイト列の始まりを示していて、これこそが BOM が UTF-8 では 3 バイト、UTF-16 では 2 バイトで済む理由です。文字そのものは変わらず、符号化が長いだけです。
12Continuation bytes BB BF10 111011 と 10 111111。それぞれ上位 2 ビットを外して残りを先頭バイトの 4 ビットのペイロードにつなげると 1111 1110 1111 1111、つまり U+FEFF になります。一度手で計算してみるのが、この印を意味不明なマジックナンバー扱いするのをやめる一番早い方法です。
3variableStart of the textファイルが本来運びたいものは、ここから始まります。シェバン行、XML 宣言、JSON の開き波括弧、CSV のヘッダ行、PHP の開始タグ。どれもが 3 バイトぶん遅れて始まることになり、この形式が引き起こす問題はすべて、その 1 つの事実の帰結です。
33A second byte-order markEF BB BF EF BB BF は、わざわざ確認する価値があるくらいよく起きます。BOM を付けるエディタが、すでに BOM のあるファイルを保存したとき、そしてファイルを連結したときです。後者では 2 つ目のファイルの BOM が結果の真ん中に埋もれ、誰の目にも触れない場所に残ります。

似た形式との見分け方

紛らわしい形式見分け方
XMLそもそも選択肢の関係ではありません。BOM は接頭辞であり、その下にあるファイルは元のままです。変わるのは、その形式自身の判別が最初に 3 バイト飛ばさなければならなくなることだけ。XML はこの問題に正面から向き合っている数少ない標準で、宣言の前にバイトオーダーマークを置くことは許し、それ以外は何も許しません。つまりあの 3 バイトは合法で、空白 1 つは違法です。
UTF-16 text3 バイトではなく 2 バイトで、リトルエンディアンなら FF FE、ビッグエンディアンなら FE FF。もっとも、見分けるのに BOM が要ることはめったにありません。UTF-16 のテキストは hex ダンプで一目瞭然だからです。ASCII の文字ごとに 00 が隣に付くので、英語の文書なら右の列に文字とゼロバイトが交互に延々と並びます。
UTF-32 textビッグエンディアンなら 00 00 FE FF、リトルエンディアンなら FF FE 00 00。後者は本当に曖昧です。同じ 4 バイトは「UTF-16 リトルエンディアンの BOM に NUL 文字が続いたもの」とも読めて、どちらの解釈を採るかは、その後ろに何が来るかを見るしかありません。
Windows-1252 text同じバイト列を、間違った前提で読んだ姿です。UTF-8 の BOM を CP1252 や Latin-1 としてデコードすると、文書の先頭に見える文字が 3 つ現れます。ウムラウト付きの i、右向きの二重山括弧、逆さの疑問符。これが見えたときは、ファイルのほうは無事で、読み手が間違っています。見た目の印象とは正反対です。

よくある壊れ方

  • スクリプトの先頭に付いた BOM。カーネルはインタプリタを見つけるためにオフセット 0 の 23 21 を探し、そこに EF BB BF を見つけます。スクリプトは「bad interpreter」や exec format error で失敗しますが、そのメッセージは BOM にも 1 行目にも触れません。しかもエディタではどう見ても完璧なファイルに見えます。
  • PHP の include に付いた BOM。3 バイトは開始タグの外側にあるので出力として数えられ、次にヘッダを設定しようとした呼び出しが headers-already-sent エラーで落ちます。しかも名指しされるのは、1 行目の上に何も無さそうに見えるファイルです。
  • CSV に付いた BOM。1 列目の名前が「BOM + 本来の文字列」になるので、ヘッダ名での照合が外れる一方、画面上のファイルは完璧に見えます。Excel はこれを意図的に書きます(Excel が UTF-8 の CSV を認識する手段がこれです)。だから、まさに意図どおりにエクスポートされたファイルで一番よく起きます。
  • JSON の先頭に付いた BOM。仕様は「実装は付けてはならない、パーサーは無視してよい」と言っていますが、Node やブラウザの背後にある JavaScript エンジンはそのどちらもせず、unexpected token エラーを投げます。しかも名指しされる文字は、どのエディタも表示せず、カーソルも乗りません。
  • 途中に紛れ込んだ BOM。cat でファイルを連結したり、テキストを追記するコードを通したりすると、2 つ目のファイルの BOM が結果の中に幅ゼロの文字として埋め込まれます。diff を生き延び、エディタでは見えず、通るはずの文字列比較を、見た目には何の理由もなく失敗させます。

この形式の現在地

この印は消えませんし、標準になることもありません。Windows のメモ帳、古い PowerShell の出力コマンドレット、Visual Studio、Excel は今もこれを書きますし、Unix 生まれのものはほぼすべて、これが付いたファイルを少し壊れたものとして扱います。現場で落ち着いた運用は「基本は BOM なしの UTF-8 で書く」、ただし例外が 1 つ。Excel で開く CSV です。ここでは、Excel がシステムのコードページを勝手に推測してアクセント付きの名前を全部壊すのを確実に止められる手段が、この印しかありません。エディタはこの選択を 2 つの別々のエンコーディングとして提示し、たいていは UTF-8 と UTF-8 with BOM という名前が付いています。両方が混ざったプロジェクトは、いずれ「変わったように見えて実は変わっていない行」の diff を生みます。一番見落とされがちなのは、この印がメタデータではなく中身だということ。Git は保存しますし、ハッシュの対象になりますし、バイト数にも含まれます。BOM のあるファイルと無いファイルは、どんなツールのどんな尺度で測っても別のファイルです。

テキスト(UTF-8 BOM)ファイルをこのサイトで開く

どれもブラウザ内で動きます。ファイルが端末から出ることはありません。

関連する形式

テキスト(UTF-8 BOM)と混同しやすい形式です。先頭バイトを見比べてください。

形式先頭バイト拡張子
XML固定の署名なし.xml
JSON固定の署名なし.json
HTML固定の署名なし.html

よくある質問

ファイルのマジックナンバーとは何ですか?

ファイル先頭の数バイトで、名前が何であろうとその形式を示すものです。PNG は必ず 89 50 4E 47 で始まり、ZIP は 50 4B 03 04 で始まります。OS もブラウザも file コマンドも、拡張子を信用せずこのバイト列を読みます。だからファイル名を変えても中身の正体は変わりません。

マジックナンバーを自分で確認する方法は?

macOS や Linux なら xxd -l 16 ファイル名 で先頭 16 バイトが表示されます。Windows なら PowerShell で Format-Hex -Path ファイル名 -Count 16 です。あるいはこのサイトのファイル形式判別ツールにドロップすれば、ローカルでバイト列を読んで形式を教えてくれます。アップロードはありません。

2 つの形式が同じマジックナンバーを持つのはなぜ?

一方が他方の上に作られているからです。docx、xlsx、pptx、apk、jar、epub はすべて中身が ZIP アーカイブなので ZIP の署名で始まり、区別するには内部のエントリを見る必要があります。Java の class ファイルと macOS のユニバーサルバイナリはどちらも CA FE BA BE で始まり、直後のフィールドで見分けます。

マジックナンバーがまったくないファイルもある?

あります。XML、HTML、JSON、SVG、CSV といったテキストベースの形式には固定のバイト署名がないため、構造から判別します。先頭の <?xml 宣言、<svg 要素、あるいは { に続く引用符付きのキーなどです。これは確定ではなく推測なので、このリファレンスではそうした形式をプローブ判別として示しています。

マジックナンバーが一致すればそのファイルは安全?

いいえ。わかるのは形式であって、中身が無害かどうかではありません。正規の PDF や docx でも悪意のあるペイロードを含んでいることがあります。特に拡張子とバイト列が食い違うときに真の形式を知るのは有用な第一段階ですが、マルウェアスキャンではありません。

テキスト(UTF-8 BOM)かもしれないファイルをお持ちですか?ファイル形式判別ツールで調べる — マジックナンバーをローカルで読み取ります。アップロードは一切ありません。またはすべての形式を見る。