イメージにはバイナリ データが含まれます。特にヌルバイト、0x00 '\0'
、. b
一部のシステム (特に Windows) では、標準 I/O呼び出しで文字を使用して、テキスト ファイルとバイナリ ファイルを区別する必要がありますfopen()
(Windows だけでなく Unix でも正常に動作します)。バイナリ データに null バイトが含まれる可能性がある場合、関数は最初の null バイトでコピーを停止するstrcpy()
ため、 et al を使用してデータのチャンクをコピーすることはできません。str*()
したがって、mem*()
開始位置と長さ、または同等のものを取る関数を使用する必要があります。
コードに適用すると、バイナリを印刷してhttpData
も%s
正しく機能しません。これ%s
は最初の null バイトで停止します。ファイルの存在を確認するために使用したのでstat()
、ファイルのサイズもあります。動的に変化するファイルに対処する必要がないと仮定すると、それはhttpData
正しいサイズに割り当てることができることを意味します。サイズを読み取りコードに渡すこともできます。これはまた、読み取りコードで を使用できfread()
、書き込みコードで を使用できることを意味し、fwrite()
文字単位の I/O を節約できます。
したがって、関数があるかもしれません:
int readHTTPData(const char *filename, size_t size, char *httpData)
{
FILE *fp = fopen(filename, "rb");
size_t n;
if (fp == 0)
return E_FILEOPEN;
n = fread(httpData, size, 1, fp);
fclose(fp);
if (n != 1)
return E_SHORTREAD;
fputs("httpData = ", stdout);
fwrite(httpData, size, 1, stdout);
putchar('\n');
return 0;
}
この関数は、成功すると 0 を返し、失敗するといくつかの事前定義された (負の?) エラー番号を返します。メモリの割り当てはルーチンが呼び出される前に行われるため、非常に簡単です。
- ファイルを開きます。失敗した場合はエラーを報告します。
- 1 回の操作でファイルを読み取ります。
- ファイルを閉じます。
- 読み取りが予期されたすべてのデータを取得しなかった場合、エラーを報告します。
- 読み取られたデータについて報告します (デバッグのみ — バイナリ データを標準出力に raw で出力することは世界で最高のアイデアではありませんが、問題のコードが行うことと同じです)。
- 成功を報告します。
元のコードにはループがあります。
int i = 0;
...
while(!feof(file)) {
fscanf(file, "%c", &httpData[i]);
i++;
}
このループには多くの問題があります。
feof()
読み取るデータが他にあるかどうかをテストするために使用しないでください。これは、EOF 指示が与えられるかどうかではなく、EOF 指示が与えられたかどうかを報告します。
- その結果、最後の文字が読み取られると、
feof()
は「false」を報告しますがfscanf()
、次の (存在しない) 文字を読み取ろうとして、それをバッファーに追加します (おそらく、ÿ、y ウムラウト、0xFF、 U+00FF、分音記号付きラテン小文字 Y)。
- コードは読み取られた文字数をチェックしないため、バッファ オーバーフローに対する保護はありません。
- を使用
fscanf()
して 1 文字を読み取るのは、 に比べてオーバーヘッドが大きくなりgetc()
ます。
size
これが に割り当てられたバイト数であると仮定して、より正確なバージョンのコードを次に示しますhttpData
。
int i = 0;
int c;
while ((c = getc(file)) != EOF && i < size)
httpData[i++] = c;
予期したときに EOF を取得することを確認できます。fread()
コードは関数内でサイズ チェックを行うことに注意してくださいfread()
。また、私が引数を書いた方法は、全か無かの命題です — すべてのsize
バイトが読み取られるか、すべてが欠落として扱われます。バイト数が必要で、短い読み取りを許容または処理する場合は、サイズ引数の順序を逆にすることができます。fwrite()
すべてが書き込まれたことを確認したい場合は、からの戻り値を確認することもできますが、出力が成功したことを確認することにはあまり注意を払わない傾向があります。(ただし、ほとんどの場合、期待どおりの入力が得られたかどうかを確認することが重要です — 入力チェックを軽視しないでください。)
ある時点で、プレーン テキスト データの場合、CRLF と NL の行末について考える必要があります。テキスト ファイルはそれを自動的に処理します。バイナリ ファイルにはありません。転送するデータが などである場合はimage/png
、おそらくこれについて心配する必要はありません。Unix を使用していて を扱っているtext/plain
場合、CRLF の行末について心配する必要があるかもしれません (しかし、私はこれについての専門家ではありません — 私は最近 (この千年紀ではない) 低レベルの HTTP のことをしていないので、ルールが変更されている可能性があります)。