yumetodoの旅とプログラミングとかの記録

旅や登山の記録やプログラミング関連の話とかフリーソフト紹介とか

拡張子とファイルのフォーマット

strimuer213p.hatenablog.com

先日Twitterでどうにも りーま氏(@strimuer213p)に拡張子とファイルのフォーマットは関係ないということが伝えられなかったので、ちょっと記事にしてみる。

ファイルの種類

まずいろんなファイルを片っ端からバイナリエディタで開いてみて欲しい。 Windowsをお使いならFavBinEditLinuxをお使いならGHexなどがいいのではないか。もちろんそんなところで宗教戦争をするつもりはないので、好きなものを使えばいい。
おれはコマンドがいいというなら、odコマンドがUnixにはあるし、GNU拡張のodコマンドはasciiの表示もしてくれる。

hex dump

さて、開いてみてわかる通り、つまるところファイルとはただ単にbyte列の羅列だ。
多くのバイナリエディタは16進数でbyte列を表示してくれるが、別に8進数で表示するもののあるし、単に見た目の問題だ。
つまりすべてのファイルは(厳密には)バイナリファイルだと言える。

これをとりあえず大きく2つに分類する。

テキストファイル

コンピュータで文字を扱うときにどうするかというと、特定のbyte列で文字を表す。文字をその特定のbyte列に直すことを、文字エンコード、と言ったりする。
この変換の規則が(広義での)文字コードである。

広義での、とぼかして書くのには理由があって、実際にはかなりややこしいことになっているのだが、

equj65.net blog.shibayu36.org

それはこの辺のサイトに説明を譲る。本題ではないからだ。

話を戻す。

とにかく、ある一つの文字コードによってエンコードされたbyte列のみで構成させるファイルをテキストファイルと呼ぶ。

(一般的な意味での)バイナリファイル

先ほど、

つまりすべてのファイルは(厳密には)バイナリファイルだと言える。

と書いたが、一般にバイナリファイルと言われて指すものはそうではなく、すべてのファイルからテキストファイルを除いたものである。

テキストファイルの種類

テキストファイルといってもさまざまな種類がある。 どういうことかというと、何らかのルールにしたがって羅列されたテキストファイル、というのがある。

例えばHTMLは、W3Cが定めたHTML規格に則って文字列を記述することで、例えばブラウザでいわゆるWebページを作れる。
Markdownは一応CommonMarkが標準規格としてあって、それにしたがって記述すれば、適当なツールでHTMLに変換できる(GFMはなんなんだという話はさておき)。
xmlは特定のデータ集合をソフトウェア間でやり取りするときに用いられ、xml上でのデータ構造そのものに意味がある。

(一般的な意味での)バイナリファイルの種類

バイナリファイルの形式は千差万別である。 C言語の構造体をそのまま書きだしたものと思ってよく、したがってバイナリファイルを扱うには処理系依存との戦いが開催される(C言語規格書の処理系依存部分との戦いの他に、エンディアン(バイトオーダー)との戦いがある)。多くのバイナリファイルフォーマットはバイトオーダーについて規定している(していないフォーマットはバグっている)。 このポータビリティ(可搬性)の低さと、多くのプログラミング言語で扱いが難しいことから、敬遠されやすい[要出典]

今日では、データが膨大になりやすい画像・音声・映像、それを格納するコンテナのフォーマットとして利用される傾向にある。

bmpは画像フォーマットの一つで、0x42 0x4dから始まる。

doc/xls/pptMicrosoft Officeで最もよく利用されていた利用されるファイルフォーマットである。

mp4は一般に映像や音声を格納するコンテナである。mp4そのものは映像フォーマットでも音声フォーマットでもないが、映像圧縮にh.264、音声圧縮にaacを使った(mp4(h.264/aac)と表記することが多い)mp4ファイルが広く流通しすぎた結果、mp4を映像フォーマットと勘違いしている人が多い。

zipはディレクトリ構造をファイルに変換すると同時に圧縮を行うことを想定しているファイルフォーマットである。もっとも圧縮は義務ではなく、複数の圧縮アルゴリズムから選択できる。一般的にはRFC 1951で規格化されたDEFLATEが圧縮アルゴリズムに採用されている。

また忘れてはいけないものとして、実行ファイルもある。Windowsなら.exeという拡張子がついている。

テキストファイルを特定のディレクトリ構造に配置したものをzip圧縮したファイルの種類

上記のようなバイナリファイルは扱いが難しいことから、複数のテキストファイルなどをzipで固めたものを独自のフォーマットとすることも多い。またこうすることで可搬性とデータサイズの小ささを両立しやすい。

こうしたファイルは特定の形式のファイルを特定のディレクトリ構造に配置したものをzipで圧縮していることを要求する。つまりzipファイルの特殊例(部分集合)である。

odt/ods/odp/odb/odg/odfはLibre Officeやその前身のOpenOfficeなどで最もよく利用されているファイルフォーマットである。実はMicrosoft Officeでも取り扱える。OpenDocument Formatと呼ばれ、ISO/IEC 26300などで標準化されている。

docx/xlsx/pptxOpenDocument Formatに対抗してMicrosoftが開発したファイルフォーマットでMicrosoft Officeで現在もっともよく利用されている。Office Open XMLと呼ばれECMA-376、ISO/IEC 29500:2008で標準化されている。

ただしここで大急ぎで補足しよう。

こう書くとバイナリファイルが2種類あると勘違いする人がいるかもしれないが断じて違う。
そもそも特定のディレクトリ構造をファイルに固めることができるファイルフォーマットはなにもzipだけではない(tarとかとか)。
zipファイルだって(一般的な意味での)バイナリファイルに含まれる
あえて数式で書けば、zip∈バイナリファイルだ。

ファイルはOSからどのように管理されるか

すこし話が変わる。FAT32とかNTFSとかext4とかという単語を聞いたことがあるだろうか?

私たちは普段ファイルを管理するのにディレクトリ(フォルダー)という概念を使っている。
これを実現しているのがさっき述べたようなディスクファイルシステムだ。

ファイル名や作成日時、更新日時、アクセス権限や、ディスクのどのセクターに書き込まれているかなどといった(例外はある)ことを管理している。

よく聞く拡張子とは、じつは単にファイル名の末尾から最初に現れた.までの文字列を(ただしファイル名の最初の文字が.の場合を除く)そう呼んでいるに過ぎない。

拡張子の役割

じつは何もない。むしろいらない。(大げさ)

しかし、人間がファイルを見てそれがどういう種類のファイルなのか判別するのにどうすればいいのかという問題がある。

バイナリファイルだけだったら、ファイルを解析して各フォーマットに固有なマジックナンバーを探すことで適切に処理ができる。それをパースして見せるソフトウェアがあれば人間はファイルの種類を判別できる。

しかしテキストファイルはそうはいかない。
xmlやhtmlのように冒頭で種類を宣言している場合はともかく、そうでない場合のほうが圧倒的多数である。

またファイルを解析するという作業は一度ファイルを開く必要があり、ディスクファイルシステムを見ればいいだけである拡張子をみる作業よりコストが高い。

そこで拡張子の出番だ。予めファイルの種類に対応する拡張子(かつてはアルファベット3文字程度が多かったが、しょっちゅう被るので最近は.vcxprojのように長いものが多い気がする)を利用者の間で決めておく。例えばWindowsでは実行ファイルはexecuteを省略して.exeを拡張子にするというコンセンサス(合意)がある。

C言語プリプロセッサとテキストファイルと拡張子

C言語を学習している人のために、もう一つ例を見てみよう。

御存知の通り、C言語ソースコード.cC言語のヘッダーファイルは.hという拡張子を主に使う。ここで

#include "a.h"

のようなソースコードC言語を学んだ人なら誰でも書いたことがあるだろうが、

#include "b.c"
#include "table.csv"

とかいうコードを見るととたんに頭がこんがらがる人いる。

これはC言語の入門書や入門サイト、はたまた学校での講義などが悪い。[要出典]

#includeはヘッダーファイルを読み込むときに使う構文ですよ。
ほら、#include <stdio.h>とかくとprintf関数が使えるでしょ?

などという嘘八百を平気で教えている。ひどいことにプリプロセッサが何かという説明すらしていないことも多い。
ハローワールドを教えた直後ならともかく、一通り教えたあとでもそんなことではお話にならないが、学校での講義や入門サイトはおおよそ例外なくそうなってしまう現状にあり[要出典]、入門書でも記述していなかったりする。
(なお独習Cは筆者にとっては残念なことに正しく解説がなされていたように思う)

C/C++にはプリプロセス時、コンパイル時、実行時の3つの世界が存在するが、

#includeとはこの内プリプロセス時にプリプロセッサによって解釈される構文だ。

機能としては、#include文を対象ファイルから消し去り、代わりに#include文で指定されたテキストファイルをその場所にコピペする、と言うものだ。

cpplover.blogspot.jp

[PDF] N4214: A Module System for C++ (Revision 2)

40年前のコピペ技術である#inludeにかわるモジュール機能の提案。

現在、C++が使っているコンパイルとリンクモデルは、C言語から受け継いだものである。各翻訳単位は、他の翻訳単位のことを一切知らずに処理される。翻訳単位を超えるには、名前リンケージ(シンボル名)を使う。名前に対応する定義はひとつだけでなければならない(ODR)。

翻訳単位の外に見える名前である外部名を、手動によるコピペで管理することを防ぐために、我々は40年前の技術である自動コピペ技術、プリプロセッサーによるヘッダーファイルを未だに使っている。これは、コンパイラーからみれば、コピペである。

ヘッダーファイルの中身はマクロによって書き換わってしまうおそれがあり、誤りの元である。

変数や関数の宣言ぐらいしか書かれていなかった昔のC言語ならば、まだ十分に耐えられたのだが、モダンなC++では、ヘッダーファイルには実行されるコードが記述されている。コンパイラーは翻訳単位ごとに重複した内容を処理しなければならず、現代のC++コンパイル時間の増大の原因になっている。

ただの自動コピペ機能なのだからテキストファイルならなんでも読み込める。まあそのあとコンパイルエラーになるかどうかは別問題であるが、それはコンパイル時のお話だ。

csvプリプロセス時読み込みはcsvに多少細工をしておくことで

qiita.com

に書いたように意味のあることに使える。

拡張子とソフトウェアの関連付け

Windows

Windowsの場合、拡張子とソフトウェアの関連付けはOSレベルで提供されている。

www.atmarkit.co.jp

もっというとレジストリに関連付け情報が記録されている。

レジストリの直接編集によるファイルの拡張子と関連づけ - Glamenv-Septzen.net

Mac

知らず

Linux

ない。なぜならばユーザーはどうせ適切なコマンドにファイルを渡すのだから。

ただ、GUI操作においては、ダブルクリックしたら適切なソフトが立ち上がらないと不便なので、ファイラーが関連付け機能を提供している。

まとめ

すべてのファイルは厳密にはバイナリファイルと言える。
すべてのファイルはテキストファイルであるかそうでないか(一般的な意味でのバイナリファイル)で分類される。
つまり、一般的な意味でのバイナリファイルとテキストファイルは全てのファイルの部分集合である。
またバイナリファイルと言っても、特にzipファイルは特定のファイルが特定のディレクトリ構造をとる場合の特殊例に名前がついていることがある(ex. xlsx)
zipファイルは一般的な意味でのバイナリファイルの部分集合であり、xlsxファイルはzipファイルの部分集合と言える。

さまざまな角度から拡張子とファイルのフォーマットについて見てきた。それぞれが全く異なるものであることがご理解いただけただろうか?そうであれば幸いだし、そうでなくても調べるきっかけくらいにはなっただろう。

をるふちゃんが懲りずにコミュニティを作ったらしいので参加した

http://wolf-cpp.hateblo.jp/entry/2017/02/15/004607wolf-cpp.hateblo.jp

ということで、自称Twitterよりきもち情報濃いめのゆるふわコミュニティに参加しました。

https://twitter.com/katainaka0503/status/831796716487733251

C++の会のSlackよりもだいぶゆるふわしている感じです。C++以外にもC#,lisp,ruby,Scala,php,go,python,Haskellなんかのチャンネルが

一応TOPページは

hackmd.io

から。


早速Wiki編集してきた

hackmd.io


追記

SlackとDiscord両方立ち上げるのが面倒なので、Franzというアプリを入れた。
Franz – a free messaging app for Slack, Facebook Messenger, WhatsApp, Telegram and more

唯一の欠点はDiscordの〜〜をプレイ中という機能が使えないことだろうか。
電卓をプレイ中は草。

FC2からはてなブログに移行した

はじめに

私は今まで http://freesofutotravel.blog94.fc2.com/ という、FC2のブログサービスを利用してほそぼそとブログを書いていたのだが、この度、はてなブログに移行した。

移行した理由

  • FC2で使っていたデザインテンプレートがHTML4.01で、HTML5にする作業をしてみたが思いの外面倒だった
  • 基本的に写真はGoogle Picasaに置いてそれを呼び出すようにしていたのだが、Google PicasaGoogle Photosになった時に、画像埋め込みリンクが簡単に取得できなくなったが、はてなブログにはGoogle Photosとの連携があるので極めて簡単に写真を貼り付けられる
  • Markdownが使える、HTML直書きしなくていい
  • はてなブログのデザインはGithub上でLESSファイルで提供されており、CSSのように人間を卒業しなくてもカスタマイズできる
  • はてなブログのデザインはレスポンシブデザインに対応している
  • はてなブログのデザインをShippableと組み合わせて自動デプロイする作業に憧れた
  • フリーソフトの旅(windows)」という前のブログのタイトルと中身があっていなかった
  • プログラマー界隈はやっぱりはてぶろ勢が多い
  • カテゴリーがFC2より柔軟

Markdownが使えるっていうのは大きいですね。wysiwygエディタは信用していないので(FC2のやつが吐くコードは糞だった)HTML直書きしていたんですが、さすがにつらみがあった。

移行のときに参考にしたもの

tsubakit1.hateblo.jp

なんかこの方は画像の移行に苦労しているけれど、ほとんどの画像はすでにGoogle Photosにあったので何もする必要がなかった。
Picasaを知る前に書いた記事2本だけはFC2に画像置いていたからこれはMarkdownで自力で書き直した。

また、この方はわざわざはてなダイアリーを経由しているが、そんなことはしなくても普通にいけた。もともとFC2ではHTML直書きしてたから、というのもあるのだろうか。 FC2のときはFC2解析を使っていたのでそのコードを各記事に埋め込んでいたのですが、それはFC2からExportしたテキストファイルの段階で消しました。

デザインの自作

できればあまりデザインを変えたくなかったのですが、FC2のブログデザインで使われている背景画像は著作権的にこっちに持ってこれないので、適当な画像を探していたら、

www.pakutaso.com

を見つけまして、ええやん、となって

github.com

一気に開発しました。

LESSJavaScriptで開発しています。いや、JavaScriptはいらないはずなんですが、ブログタイトルのmarginpaddingを弄って背景画像とブログ記事の開始位置の相対位置を固定したくて使ってます。CSSだけだとまだ動的に幅の参照とかできないはず。HTML構造ごと変えればCSSだけにできるけどだるいのでJavaScript使ってます。

追記: CSSvw単位を使うことでできたのでJavaScriptはいらなくなった。

github.com

書いたLESSとJavaScriptはShippableというCIに投げつけて、LESSはCSSにしてminify、JavaScriptGoogle Closure Compilerでminify&ES5化してます。この辺は後でQiitaにでも書く予定。

追記

qiita.com

書いた。

不満な点

HTTPS化できないことかな。

かと言ってサーバー立ち上げたり借りたりしてWordPress使う気にはなれなかったし、 友人が

173210's Blog

でやってるみたいにGithub pages使うことも考えたけど、それはそれでコメントシステムとかどうすんの?という思いがありはてなブログ使っているけど。

まだ移行できていないもの

雲取山に登山した記事

雲取山に登山した記事で国土地理院の地図に書き込みしたものを公開しているのだが、国土地理院側の仕様変更がいつのまにかあったらしく壊れていた。今ちまちまコンバーターを書いている。

追記(2018/1/8)

github.com

github.com

変換完了した。

SyntaxHighlighter

はてなブログにはもともとSyntaxHighlightしてくれるやつがあるっぽい。実際使ってみたが、正直気に入らない。 あとインポートした記事のSyntaxHighlightは記法がちがうのかうまく行ってないのでどのみちSyntaxHighlighterが必要そうだ。

追記

試しに有効にしたらMaximum call stack size exceededとでて、かつトップバーが読み込まれないので、あきらめモード。data-unlink=""とかそういう問題じゃない。 minifyされてないSyntaxHighlighterで試したらなんかそこかしこで無限再帰している。はてなブログのなにが干渉しているのだろう。かといってiframesrcdoc使うのはなぁ・・・。

広告が表示されない

これは大問題だ。 Imgur この12個のエラー、どうにかならないのか・・・。

元記事からのリダイレクト

これどうすっかな・・・。まあJavaScriptで書くんだけど、URLががらっと変わってるもんで、厳密に各記事をリダイレクトするには変換テーブルを持っておく必要があるな・・・。