2013年10月27日日曜日

ファイルのカット:複数のファイルオープンを行わない方法

ファイルの一部分をカットし、保存し直す例題です。

ファイルの分割や、一部を切り出して別のファイルに書き出す等の例題では、fopen にてファイルポインタを複数用いて別ファイルとして書き出すことが考えられますが(例題を準備するまでもなくいくらでも検索にヒットするでしょう)、ファイルポインタの操作では、追加書き込みしかできないため、同一ファイル上で一部分をカットし保存し直すことが不可能です。
そこで、本例題ではファイルディスクリプタを用いて、同一ファイル上の操作を行っています。

本来はこの例題にて 64bit 長のファイルサイズにも対応したものを準備したかったのですが、開発環境側の準備も必要になりますのでそちらが準備できれば両環境に対応した例題に修正して再度掲載すると言う形になります(OSX ではこのままでも 64bit 対応可能のようです)。
※ 64bit 版として利用する場合には、off64_t/lseek64 への置き換えが必要(Linux etc.)
64bitファイル対応に関して

この例題では、ftruncate にてファイルサイズを切り詰めて保存しているのですが、この関数はファイルの後半部を切り詰めたり伸長することしか対応しておらず、while 分のようにファイルの後半部分を前半に移動し直すと言う作業が必要となっています。
後半部分だけをカットする場合にはこの関数のみでも対応は可能ですが、前半部分をカットできないために下記のような例題となります。
実行結果

64bitファイル対応に関して

最近のOSやプラットフォームでは64bitのファイルシステムが当たり前となっていますが、C言語(gcc/g++)においてそれがいつからサポートされているのかは開発環境のアップデートやら何やらをひと通り準備してからでないといけなくなります。

つい最近、Android にて 2G 以上のファイルが対応できない壁にぶち当たりちょっと気になっているところです。

Android/NDK での対応:現状サポートされていない
・SD が FAT32 フォーマット
・libc が 64bit をサポートしていない

Windows での 64bit 対応:
fseek/_fseeki64:VC++ にて利用可能

OSX や Linux での対応:
FSEEKO:コンパイラ等に -D_FILE_OFFSET_BITS=64 を指定して利用可能

一方、Snow Leopard 64bit で下記のソースを実行すると、コンパイラに何も指定しなくても普通にシークはできています(off_t のサイズも64bitになっています)。 実行結果: 私の環境では(Snow Leopard 64bit/Xcode 4.2)、lseek64/llseek/_llseek 等がサポートされていないのですが、XCode をインストールした際に 64bit 対応としてくれているのかもしれません。

LSEEK64 のページによると、
関数 lseek64() は glibc 2.1 以降で使用可能であり、 llseek() のエイリアスとして定義されている。
とあるので gcc 側の対応としてはそちらが正解なのでしょうが、Apple が 64bit に対応した gcc をインストールしてくれていると言うことになるんでしょうかね??

一応 MacPorts での gcc/glibc 等のアップデート方法を試みたのですが、libgcc のインストールにてコケてしまいあえなく中断・・現行のままで利用可能と言うことにしておきましょう。