プリント基板設計・シミュレーション

TOP > アポロレポート > コラム > 第23回 プログラミングについて 『テキストファイルの話』
コラム
2022/11/29

第23回 プログラミングについて 『テキストファイルの話』

アポロレポート

『テキストファイルの話』

 

  テキストファイルの話。DOSやWindowsでテキストファイルを扱っていてテキストファイルの構造に疑問をもった方はあまり多くはないかと思います。もっともこれはこのOSだけの話ではなく、単一のOSのみを扱っているのであればテキストファイルの構造は同じですから気になる方が変なのかも知れません。

 もともと私はVAX/VMSでの仕事が長かったので、初めてDOSやWindows、またUNIXを扱ったときには面食らいました。というよりもC言語でプログラムを書き始めたときと言った方が正解かもしれません。

 VAX/VMSの標準のテキストファイルの構造は、可変長レコード形式と呼ばれているもので、1つの行のデータの先頭に2バイトの情報が付加されたものです。この2バイトに行のバイト数が記述されるようになっています。当然2バイトということは最大でも1行が65535バイトの制限がありますが、この長さが問題となったことはありませんでした。

 □□ABCDEFG
 |
 |この部分に行のバイト数(この場合は7)が記述される。

 このファイル形式の欠点は最大長の制限があることですが長所も当然あります。
1つはテキストファイルであってもバイナリーデータをそのまま書き込めることです。
当然ヌル文字であっても構いません。ですからこの形式のファイルがテキストファイルのみに使用されるというわけではありません。もう1つの長所はファイル内を検索するときに次の行の先頭がこの2バイトの数値を読み込むだけで分かることです。
 もっともこのような面倒くさいことはOSが勝手に行なってくれますので、通常は気にすることなしに扱います。

 余談ですがVMSというOSのにはレコードの構造とアクセスの方法との2つの構造があってこの2つの組み合わせでファイルが成立するようになっていました。レコードの構造には、可変長レコード、固定長レコード、ストリーム形式レコード、セグメントレコードなどがあり、アクセスの方法にはシーケンシャルアクセス、ランダムアクセス、キードアクセスなど様々なものがありました。これらの情報が1ブロックのファイルヘッダに記述されていてOSが管理しているのです。FORTRANでこれらのファイルを処理しようとすると、これらのファイルの属性が合わずにオープンすらできないなどということも多々ありました。

 DOSやWindowsで扱うファイルのレコードの形式にはとくにファイルそのものには何も属性はありません。テキストファイルには伝統的にストリーム形式が使用されているだけです。慣れてしまえな何も不思議はないのですが、私のような他のOSから移籍してきた人間には異様な感じがするものです。

 そもそもこのようにファイルのレコード形式を規定しないファイルシステムはUNIXがその源になっています。「ファイルの処理はプログラムにまかせるようにしよう」という考え方はじつは画期的な考えだったのです。このようにすることでファイルシステムをスッキリすることができたのです。ただテキストファイルのみは何か形式を決めておこうという訳でストリーム形式が採用されました。

 さてこのストリーム形式とはどんな形式かというと、

 ABCDEFG<LF>
 ABCDEFG<CR><LF>
 ABCDEFG<CR>

 というように文字列の最後に<LF>コードなどの文字列の終了を表すコードを挿入するものです。ちなみにこのコードはOSによって次のように違いがあります。

 <LF>   UNIX
 <CR><LF> DOS、Windows
 <CR>   Mac

C言語での標準関数 fprintf は、

 fprintf(fp,"ABCDEFG\n");

と改行を¥nで表現しますが、このコードは実際には<LF>になります。C言語の本家であるUNIXではこれがそのままファイルに記述されるのですからごく当然なことですが、DOSやWindowsでは、これを<CR><LF>という2文字にしなければなりません。この操作は fopen 関数でファイルをテキストモードでオープンしたときに関数の内部で行われます。UNIXと比べると不自然と言えます。

 このように printf 関数とファイルの内容を比べるとDOSやWindowsの方が不自然なのですが、これを実際のディスプレイ上での表示で考えると、<CR>は現在の行の先頭にカーソルを移動する命令として扱われ、<LF>はカーソルの位置はそのままで次の行に移動する命令として扱われますので、このように考えるとUNIXの方が不自然と言えます。まあ一長一短があるというところでしょうか。

 さてこのストリーム形式ですが、大きな問題点は文字列中に文字列の終了を示す文字をいれることができないということです。

 fprintf(fp,"abc\ndef\n");

というようにプログラムを作って実行すると当然のことですが、 abc と def が別々の行として表示されます。またこのファイルを読み込むプログラムでもこれは別々の行となってしまいます。更にC言語の問題点ではありますが、文字列の中にヌル文字を入れることができません。1つの行としては認識して読み込むのですが、C言語の標準関数ではこのヌルで文字列の終わりと判断してしまうのです。
 長所と言えば1行がどんなに長くても問題がないことです。またC言語はファイルの入出力に1文字単位の関数があるのでこの形式の方が便利のような気がします。VAX/VMSでFORTRANを使ってファイルの入出力するときは、必ずレコード単位での入出力となるのでC言語で作ったファイルの処理をするときにはまた問題が発生します。VMSのレコード管理やユーザ環境の管理がしっかりしていて(しっかりし過ぎているとも言えますが)、ユーザに許されている長さ以上のレコードを読むことOSに叱られてしまうのです。こういうときには入出力の部分をC言語で書いておくか、ファイルのヘッダを実行時に強制的に書き換えて違ったレコード形式として読み込むかのいずれかの手法で回避しなければなりません。

 このようなテキストファイルに対してランダムアクセスを行うときにはどのような動作になるか考えてみましょう。

 可変長レコード形式のファイルの場合、現在のレコード1つ前のレコードに戻りたいとしたとき、前のレコードの先頭を覚えていればそこに移動することは簡単ですが、そうでないときにはとんでもないことをしなければなりません。1つ前の位置の文字を読んで1文字づつ戻していったとしてもどれがレコードの先頭か分からないのです。ということはファイルの先頭から順に読んでいかなけれなならないということになります。
 実際に私がVMS上でこのようなことをFORTRANの覚えたてのころに行なったことがあります。FORTRANには1つ前ののレコードに移動するというBACKSPACEという便利な命令文があるのでこれを利用しました。次のように記述すると1つ前のレコードに戻ってくれるのです(引数の1はファイルの装置番号です)。

 BACKSPACE(1)

 ものすごく簡単に実現できるのですが、ファイルの末端近くでこれを行なうとこれがメチャクチャ遅いです。当時はこの原因についてはまったく分からなかったので「こんなものなのかなあ」と思いつつも使っていました。

 これに対してストリーム形式のときにはレコードの末端を示す文字が現れるまで1文字づつ前の文字を読んでいけばいいのでこちらの方は問題はないかと思われます。もっともC言語の関数にはファイルをシークする関数が充実していますので、状況に合った関数を使用すればいいのですが...。

 テキストファイルには通常ファイルの終わりを示すコードが挿入されています。
DOSやWindowsではctrl/zがそれですが、この2つのOSではファイルを示すコードの存在が曖昧なところがあります。あってもなくてもいいのです。次のようにファイルの最後の部分が次のように何種類か存在しています。

 (1) <CR><LF>^Z
 (2) <CR><LF>
 (3) ^Z
 (4)

(1)(2)は最後の行が完結しています。(3)(4)は最後の行は完結していませんが、このデータを扱うプログラムによっては完結していると判断することもあります。例えばVZエディタなどでこのファイルを開いて見ると、

 (1)...
    [EOF]

 (2)...
    [EOF]

 (3)...[EOF]

 (4)...[EOF]

となってEOFを示す位置が違ってきます。他のエディタでは(3)(4)が(1)や
(2)と同じになるものもあります。

 それに比べ、UNIXでのテキストファイルは最後の行は必ず完結しているものとみなすようです。またファイルの終わりを示すコードの挿入もされません。
ですからファイルの最後の部分は、

 <LF>

となっている訳です。

 またここで問題になることがあります。DOSやWindowsのテキストファイルをUNIXにftpなどで転送し、viエディタで開いてみると^Zの文字がファイルの最後の部分に表示されるのです。この^ZがDOSやWindowsのテキストファイルの終わりを示すコードなのです。

 テキストファイルの構造には様々なものがありますので、なにか問題が発生したときなどは今回お話したことを少しだけ思い出して下さい。ではまた次回。


そのお悩み、
アポロ技研に話してみませんか?

アポロ技研でワンランク上の物創りへ!
そのお悩み、アポロ技研に話してみませんか?