gzipファイルアクセス関数
このライブラリは、「gz」で始まる関数を使い、stdioに似たインターフェイスで
gzip(.gz)形式のファイルの読み書きに対応します。gzip形式はzlib形式とは異なります。
gzipはdeflateストリームをRFC 1952に記載されたgzipラッパーで包んだものです。
typedef struct gzFile_s *gzFile; /* 一部が不透明なgzipファイル記述子 */
gzopen
ZEXTERN gzFile ZEXPORT gzopen(const char *path, const char *mode);
pathにあるgzip(.gz)ファイルを、読み込みと展開、または圧縮と書き込みのために開きます。
modeはfopenと同様に「rb」「wb」などを指定しますが、圧縮レベル(「wb9」)や方針も含められます。
フィルター後のデータには「wb6f」のように'f'、Huffmanのみの圧縮には「wb1h」のように'h'、
ランレングス符号化には「wb1R」のように'R'、固定符号の圧縮には「wb9F」のように'F'を指定します。
(strategyの詳細はdeflateInit2の説明を参照してください。)'T'は圧縮せず、gzip形式も
使わない透過的な書き込み・追記を要求します。'T'で透過的な読み込みを強制することはできません。
先頭にgzipヘッダーがなければ、自動的に透過的な読み込みを行います。'G'オプションで透過的な
読み込みを無効にできます。その場合、gzipヘッダーがなければエラーを返します。
'N'はノンブロッキングモードでファイルを開きます。
'w'の代わりに'a'を使うと、書き込むgzipストリームをファイルへ追記するよう要求できます。
同じgzipファイルの読み書きには対応していないため、'+'はエラーになります。
書き込み時に'x'を加えると排他的にファイルを作成し、すでに存在すれば失敗します。
対応するシステムでは、読み書き時に'e'を加えると、execve()呼び出し時にファイルを閉じる
フラグを設定します。
これらの関数はgzipと同様、ファイル内に連続するgzipストリームを読み、デコードします。
gzopen()の追記機能でそのようなファイルを作れます。(別の方法はgzflush()も参照してください。)
追記時のgzopenは、ファイルの先頭がgzipストリームかどうかを検査せず、追記開始位置を
決めるためにgzipストリームの終端を探すこともしません。gzopenは既存ファイルへ
gzipストリームを単に追記します。
gzopenはgzip形式でないファイルの読み込みにも使えます。その場合、gzreadは
展開せず、ファイルから直接読み込みます。読み込み時は、gzipヘッダーの識別用2バイトを
調べて自動的に判別します。
gzopenは、ファイルを開けなかった場合、gzFile状態を確保するメモリが足りない場合、
または不正なmode('r'、'w'、'a'のいずれもない、または'+'がある)を指定した場合にNULLを返します。
gzopenの失敗理由がファイルを開けなかったことかどうかは、errnoを調べて判別できます。
ノンブロッキングのためmodeに'N'があると、ブロックを避けるためopen()自体が失敗する場合があります。
その場合、gzopen()はNULLを返し、errnoはEAGAINまたはENONBLOCKになります。
その後、gzopen()を再試行できます。ファイルを開く際にはブロックしたい場合、
O_NONBLOCKなしのopen()を使い、そのファイル記述子と'N'を含むmodeをgzdopen()へ渡せます。
これによりノンブロッキングに設定します。
gzdopen
ZEXTERN gzFile ZEXPORT gzdopen(int fd, const char *mode);
ファイル記述子fdにgzFileを関連付けます。ファイル記述子はopen、dup、creat、pipe、
fileno(すでにfopenで開いたファイルの場合)などの呼び出しから得ます。
modeはgzopenと同じです。modeの'e'はexecve()呼び出し時にファイルを閉じるfdのフラグを
設定します。'N'はfdのノンブロッキングフラグを設定します。
返されたgzFileに対する次のgzcloseは、fclose(fdopen(fd, mode))と同様、ファイル記述子fdも
閉じます。fdを開いたままにするには、fd = dup(fd_keep); gz = gzdopen(fd, mode);を使ってください。
gzdopenは失敗時にfdを閉じないため、リークを避けるよう、複製した記述子を保存するべきです。
FILE *からfileno()でファイル記述子を得る場合は、二重に閉じることを避けるためdup()を使う必要が
あります。gzclose()とfclose()はどちらも関連付けられたファイル記述子を閉じるため、
それぞれ異なる記述子が必要です。
gzdopenは、gzFile状態を確保するメモリが足りない場合、不正なmode
('r'、'w'、'a'のいずれもない、または'+'がある)を指定した場合、またはfdが-1の場合にNULLを返します。
次のgz*による読み込み、書き込み、シーク、クローズまでは記述子を使わないため、
gzdopenはfdが-1でない限り、不正な記述子を検出しません。
gzbuffer
ZEXTERN int ZEXPORT gzbuffer(gzFile file, unsigned size);
fileに対してこのライブラリの関数が使う内部バッファーのサイズをsizeに設定します。
既定のサイズは8192バイトです。gzopen()またはgzdopen()の後、ファイルを読み書きする
ほかの呼び出しより前に呼び出さなければなりません。バッファーメモリの確保は常に最初の読み書きまで
遅延します。指定サイズの3倍のバッファー領域を確保します。例えば64Kや128Kバイトへ大きくすると、
展開(読み込み)の速度が目に見えて上がります。
新しいバッファーサイズは、gzprintf()の最大長にも影響します。
gzbuffer()は、成功時に0、呼び出しが遅すぎた場合などの失敗時に-1を返します。
gzsetparams
ZEXTERN int ZEXPORT gzsetparams(gzFile file, int level, int strategy);
fileの圧縮レベルと方針を動的に更新します。引数の意味はdeflateInit2の説明を
参照してください。パラメーター変更を適用する前に、すでに渡されたデータをフラッシュします。
gzsetparamsは、成功時にZ_OK、書き込み用に開いていなければZ_STREAM_ERROR、
フラッシュしたデータの書き込みエラー時にZ_ERRNO、メモリ確保エラー時にZ_MEM_ERRORを返します。
gzread
ZEXTERN int ZEXPORT gzread(gzFile file, voidp buf, unsigned len);
fileから非圧縮データで最大lenバイトを読み、展開してbufへ入れます。入力ファイルがgzip形式で
なければ、gzreadは指定したバイト数をファイルから直接バッファーへコピーします。
入力内のgzipストリームの終端に達すると、gzreadは次のgzipストリームを探して読み込みを
続けます。入力ファイルには任意の数のgzipストリームを連結でき、gzread()はすべて展開します。
gzipストリームの後にgzipストリームでないデータがあれば、その残りの不要なデータは無視し、
エラーも返しません。
gzreadは、同時に書き込まれているgzipファイルを読むためにも使えます。
入力の終端に達すると、gzreadは利用可能なデータを返します。gzerrorが返すエラーコードが
Z_OKまたはZ_BUF_ERRORなら、gzclearerrでファイル終端表示を解除して、gzreadを再試行できます。
Z_OKは直前のgzreadでgzipストリームが完了したことを示し、Z_BUF_ERRORは入力ファイルが
gzipストリームの途中で終わったことを示します。不完全なgzipストリームではgzreadは-1を
返さないことに注意してください。このエラーはgzclose()まで遅延し、直前のgzreadがgzip
ストリームの途中で終わっていればZ_BUF_ERRORを返します。代わりに、gzcloseより前にgzerrorで
この状態を検出することもできます。
gzreadはノンブロッキングデバイス上のgzipファイルを読むためにも使えます。入力が滞り、
返せる非圧縮データがなければ、gzread()は-1を返し、errnoはEAGAINまたはEWOULDBLOCKになります。
その後、gzread()を再び呼び出せます。
gzreadは実際に読んだ非圧縮バイト数を返します。ファイル終端ではlen未満、エラー時は-1です。
lenがintに収まらないほど大きければ何も読まず、-1を返してエラー状態をZ_STREAM_ERRORに設定します。
エラー前にデータを読んでいれば、そのデータを使い切るまで返し、その後の次の呼び出しでエラーを示します。
gzfread
ZEXTERN z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems,
gzFile file);
fileから、1項目あたりsizeバイトのデータを最大nitems項目読み、展開してbufへ入れます。
それ以外の動作はgzread()と同じです。stdioのfread()と同じインターフェイスを、size_tの
要求・戻り値の型で提供します。ライブラリがsize_tを定義していれば、z_size_tはsize_tと同じです。
そうでなければ、z_size_tはポインターを収容できる符号なし整数型です。
gzfread()はsizeバイトの完全な項目を読んだ数を返します。ファイル終端に達して完全な項目を
読めなかった場合、またはエラー時には0を返します。0を返した場合は、エラーの有無を判別するために
gzerror()を調べなければなりません。sizeとnitemsの積がオーバーフローしてz_size_tに収まらなければ、
何も読まず、0を返し、エラー状態をZ_STREAM_ERRORに設定します。
ファイル終端に達し、最後に項目の一部しかない場合(残りの非圧縮データ長がsizeの倍数でない場合)でも、
その最後の不完全な項目をbufへ読み込み、ファイル終端フラグを設定します。読んだ不完全な項目の長さは
提供しませんが、gztell()の結果から推測できます。一般的なライブラリのfread()も同じ動作です。
同時に書き込まれるファイルやノンブロッキングファイルをsize != 1で読む場合、データが失われる可能性が
あります。その場合はsize == 1またはgzread()を使ってください。
gzwrite
ZEXTERN int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len);
gzfwrite
ZEXTERN z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size,
z_size_t nitems, gzFile file);
bufから、1項目あたりsizeバイトのデータをnitems項目圧縮してfileへ書き込みます。
stdioのfwrite()と同じインターフェイスを、size_tの要求・戻り値の型で提供します。
ライブラリがsize_tを定義していればz_size_tはsize_tと同じです。そうでなければ、z_size_tは
ポインターを収容できる符号なし整数型です。
gzfwrite()はsizeバイトの完全な項目を書いた数を返し、エラー時には0を返します。
sizeとnitemsの積がオーバーフローしてz_size_tに収まらなければ、何も書かず、0を返し、
エラー状態をZ_STREAM_ERRORに設定します。
同時に読まれるファイルやノンブロッキングファイルをsize != 1で書く場合、項目の一部だけを
書く可能性があり、どれだけ書かれなかったかを知る手段がないため、データが失われることがあります。
その場合はsize == 1またはgzwrite()を使ってください。
gzprintf
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
ZEXTERN int ZEXPORTVA gzprintf(gzFile file, const char *format, ...);
#else
ZEXTERN int ZEXPORTVA gzprintf();
#endif
fprintfと同様、format文字列に従って引数(...)を変換、整形、圧縮してfileへ書き込みます。
gzprintfは実際に書いた非圧縮バイト数を返し、エラー時には負のzlibエラーコードを返します。
書き込む非圧縮バイト数は8191、またはgzbuffer()へ指定したバッファーサイズより1少ない値が
上限です。呼び出し側はこの上限を超えないようにするべきです。超えた場合、gzprintf()は
何も書かずにエラー(0)を返します。
この最後の場合には、予測不能な結果を招くバッファーオーバーフローも起こり得ます。
ただし、安全なsnprintf()とvsnprintf()が使えなかったため、zlibを安全でないsprintf()や
vsprintf()でコンパイルした場合に限ります。それは非ANSI Cコンパイラーの場合だけです。
安全な関数が使えず、gzprintf()を安全でないまま提供することも選べなかったため、
gzprintf()なしでzlibをビルドしている可能性もあります。その場合、gzprintf()は
Z_STREAM_ERRORを返します。これらの可能性はすべてzlibCompileFlags()で判別できます。
Z_BUF_ERRORを返した場合、ノンブロッキングの書き込み先が滞ったため、何も書き込まれていません。
gzputs
ZEXTERN int ZEXPORT gzputs(gzFile file, const char *s);
指定したnull終端文字列sを、終端のnull文字を除いて圧縮し、fileへ書き込みます。
gzputsは書き込んだ文字数を返し、エラー時には-1を返します。
書き込み先がノンブロッキングなら、書き込んだ文字数が文字列の長さより少ない場合があります。
文字列の長さがintに収まらなければ、-1を返して何も書き込みません。
gzgets
ZEXTERN char * ZEXPORT gzgets(gzFile file, char *buf, int len);
fileからバイトを読み、展開してbufへ入れます。len-1文字を読むか、改行文字を読んでbufへ
転送するか、ファイル終端に達するまで続けます。文字を読んだ場合、またはlenが1の場合、
文字列をnull文字で終端します。ファイル終端のため文字を読めなかった場合、またはlenが1未満なら、
バッファーは変更しません。
gzgetsはnull終端文字列であるbufを返し、ファイル終端またはエラー時にはNULLを返します。
エラー前にデータを読んでいれば、そのデータを使い切るまで返し、その後の次の呼び出しで
NULLを返してエラーを示します。
gzgetsはgzread()と同様、同時に書き込まれているファイルやノンブロッキングデバイスにも
使えます。ただし行が途中で分かれる場合があり、必要に応じた再結合はアプリケーションが行います。
gzputc
ZEXTERN int ZEXPORT gzputc(gzFile file, int c);
cをunsigned charへ変換し、圧縮してfileへ書き込みます。gzputcは書き込んだ値を返し、
エラー時には-1を返します。
gzgetc
ZEXTERN int ZEXPORT gzgetc(gzFile file);
fileから1バイトを読み、展開します。gzgetcはそのバイトを返し、ファイル終端または
エラー時には-1を返します。エラー前にデータを読んでいれば、そのデータを使い切るまで返し、
その後の次の呼び出しで-1を返してエラーを示します。
速度のためマクロとして実装しています。そのため、ほかの関数が行う検査をすべては行いません。
fileがNULLかどうかも、fileが指す構造体の内容が壊されているかどうかも検査しません。
gzgetcはノンブロッキングデバイス上のgzipファイルを読むためにも使えます。
入力が滞り、返せる非圧縮データがなければ、gzgetc()は-1を返し、errnoは
EAGAINまたはEWOULDBLOCKになります。その後、gzread()を再び呼び出せます。
gzungetc
ZEXTERN int ZEXPORT gzungetc(int c, gzFile file);
cをfileのストリームへ押し戻し、次の読み込みの最初の文字として読めるようにします。
少なくとも1文字の押し戻しは常に許されます。gzungetc()は押し戻した文字を返し、
失敗時には-1を返します。cが-1ならgzungetc()は失敗し、すでに押し戻した文字が
まだ読まれていない場合も失敗する可能性があります。gzopenまたはgzdopenの直後に
gzungetcを使う場合、少なくとも出力バッファーサイズ分の文字を押し戻せます。
(前述のgzbufferを参照してください。)gzseek()またはgzrewind()でストリームの位置を
変えると、押し戻した文字は破棄します。
gzungetc(-1, file)は、保留中のシークを強制的に実行します。その後、要求したシークが
ファイル終端に達していても、gztell()は位置を報告します。これを使えば、gzipファイルを
バッファーへ読み込まずに、非圧縮バイト数を求められます。
gzflush
ZEXTERN int ZEXPORT gzflush(gzFile file, int flush);
gzseek
ZEXTERN z_off_t ZEXPORT gzseek(gzFile file,
z_off_t offset, int whence);
fileに対する次のgzreadまたはgzwriteの開始位置を、whenceを基準とするoffsetへ設定します。
offsetは非圧縮データストリーム内のバイト数です。whenceはlseek(2)と同じ定義ですが、
SEEK_ENDには対応していません。
読み込み用のファイルではこの関数をエミュレートしますが、極めて遅い場合があります。
書き込み用では前方へのシークだけに対応し、gzseekは新しい開始位置までゼロの列を圧縮します。
読み書きのどちらでも、実際のシークは次の読み書きまで遅延し、書き込み時にはクローズ操作でも
実行します。
gzseekは結果の位置を非圧縮ストリームの先頭からのバイト数で返し、エラー時には-1を返します。
特に、書き込み用に開いたファイルで新しい開始位置が現在位置より前になる場合はエラーです。
gzrewind
ZEXTERN int ZEXPORT gzrewind(gzFile file);
gztell
ZEXTERN z_off_t ZEXPORT gztell(gzFile file);
gzoffset
ZEXTERN z_off_t ZEXPORT gzoffset(gzFile file);gzeof
ZEXTERN int ZEXPORT gzeof(gzFile file);
読み込み中にfileのファイル終端表示が設定されていれば真(1)、それ以外は偽(0)を返します。
終端表示を設定するのは、入力の終端を超えて読もうとして、要求量を満たせなかった場合だけです。
そのためfeof()と同様、最後の読み込み要求が入力ファイルに残るバイト数とちょうど同じだった場合、
読むデータがもうなくてもgzeof()は偽を返すことがあります。
入力ファイルのサイズがバッファーサイズの整数倍なら、これが起こります。
gzeof()が真を返せば、読み込み関数はそれ以上データを返しません。ただし、gzclearerr()で
終端表示をリセットし、前回の終端検出後に入力ファイルが大きくなっていれば、再びデータを返せます。
gzdirect
ZEXTERN int ZEXPORT gzdirect(gzFile file);
読み込み中にfileを直接コピーしていれば真(1)、gzipストリームを展開していれば偽(0)を返します。
空の入力ファイルにはgzipストリームがないため、gzdirect()は真を返します。
gzopen()またはgzdopen()の直後にgzdirect()を使うと、gzipファイルかどうかを判別する
読み込みのためにバッファーを確保します。そのためgzbuffer()を使う場合は、gzdirect()より前に
呼び出すべきです。同時に書き込まれる入力やノンブロッキングデバイスでは、入力が4バイト蓄積した後に
gzdirect()の答えが変わる場合があります。gzipヘッダーの有無を確認するには4バイトが必要です。
それより前はgzdirect()は真(1)を返します。
書き込み時のgzdirect()は、透過的な書き込み(gzopen()のmodeに「wT」)を要求した場合に
真(1)、それ以外は偽(0)を返します。(注:書き込み時にgzdirect()は必要ありません。
透過的な書き込みは明示的に要求する必要があるため、アプリケーションは答えをすでに知っています。
静的リンク時にgzdirect()を使うと、gzipファイルの読み込みと展開に関するzlibコードを
すべて取り込むため、望ましくない場合があります。)
gzclose
ZEXTERN int ZEXPORT gzclose(gzFile file);
gzclose_r
ZEXTERN int ZEXPORT gzclose_r(gzFile file);
ZEXTERN int ZEXPORT gzclose_w(gzFile file);
gzerror
ZEXTERN const char * ZEXPORT gzerror(gzFile file, int *errnum);
fileで最後に発生したエラーのメッセージを返します。errnumがNULLでなければ、*errnumを
zlibのエラー番号に設定します。圧縮ライブラリではなくファイルシステムでエラーが起こった場合は、
*errnumをZ_ERRNOに設定し、アプリケーションはerrnoで正確なエラーコードを調べられます。
アプリケーションは返された文字列を変更してはいけません。この関数を後で呼び出すと、
以前返した文字列が無効になる場合があります。fileを閉じれば、以前にgzerrorが返した
文字列は使用できなくなります。
上述の関数のうち戻り値でエラーとファイル終端を区別しないものでは、gzerror()を使って
両者を区別するべきです。
gzclearerr
ZEXTERN void ZEXPORT gzclearerr(gzFile file);
fileのエラーフラグとファイル終端フラグを解除します。stdioのclearerr()と同様です。
同時に書き込まれているgzipファイルを読み続ける場合に役立ちます。
#endif /* !Z_SOLO */