2

このコードには、1 組 (またはそれ以上) の目を使用できます。ファイルストリーム(f1)から配列/バッファ(ファイルはテキストファイル、配列はchar型)に一定量のバイトを読み込もうとしています。サイズ「buffer - 1」で読み取った場合、配列を「再割り当て」し、中断したところから読み取りを続行します。基本的に、未知のサイズのファイルのバッファを動的に拡張しようとしています。私が疑問に思っていること:

  1. 私はこれを間違って実装していますか?
  2. コードをそのまま使用して、「realloc」などの障害条件を確認するにはどうすればよいですか?
  3. 「組み込み関数reallocの暗黙の宣言...」についてコンパイルすると、多くの警告が表示されます(read、malloc、strlenなどの使用についてもその警告が表示されます.
  4. 「read()」が 2 回目 (および 3 回目、4 回目など) に呼び出されると、毎回ストリームの先頭から読み取られますか? それは私の問題かもしれませんが、最初の「buff_size」文字のみを返すようです。

スニペットは次のとおりです。

//read_buffer is of size buff_size
n_read = read(f1, read_buffer, buff_size - 1);
read_count = n_read;
int new_size = buff_size;
while (read_count == (buff_size - 1))
{

        new_size *= 2;
        read_buffer = realloc(read_buffer, new_size);
        n_read = read(f1, read_buffer[read_count], buff_size - 1);
        read_count += n_read;
}

この種の動的読み取りを行う方法を学んでいるので、誰かがこの種のベストプラクティスについていくつかの簡単な事実を述べることができるかどうか疑問に思っています. これはプロの世界でトンになると思います(未知のサイズのファイルを読む)?御時間ありがとうございます。ALSO: 物事を行うための良い方法 (つまり、この種の問題に対するテクニック) を見つけたとき、それをどのように行ったかを覚えていますか、それとも将来参照できるように保存していますか (つまり、解決策はかなり静的です)?

4

3 に答える 3

6

とにかくファイル全体のバッファーを拡張する場合は、おそらく最後までシークし、現在のオフセットを取得してから、最初に戻ってシークし、一挙に読み取るのが最も簡単です。

size = lseek(f1, 0, SEEK_END); // get offset at end of file

lseek(f1, 0, SEEK_SET); // seek back to beginning

buffer = malloc(size+1); // allocate enough memory.

read(f1, buffer, size);  // read in the file

あるいは、適度に最新の POSIX ライクなシステムでは、 の使用を検討してmmapください。

于 2012-05-02T19:00:48.993 に答える
2

ここにクールなトリックがあります:mmap代わりに使用してください(manmmap)。

一言で言えば、バイトf1のファイルにファイル記述子があるとしましょう。nbあなたは単に電話します

char *map = mmap(NULL, nb, PROT_READ, MAP_PRIVATE, f1, 0);
if (map == MAP_FAILED) {
    return -1; // handle failure
}

終わり。

すでにメモリ内にあるかのようにファイルから読み取ることができ、OSは必要に応じてページをメモリに読み込みます。終わったら、電話するだけです

munmap(map, nb);

マッピングがなくなります。

編集:私はあなたの投稿を読み直したところ、ファイルサイズがわからないことがわかりました。なんで?

lseekファイルの最後までシークし、現在の長さを知るために使用できます。

代わりに、読み取り中に他の誰かがファイルに書き込んでいることが原因である場合は、現在のマッピングからファイルがなくなるまで読み取り、lseekもう一度呼び出して新しい長さを取得し、を使用mremapしてサイズを大きくすることができます。または、新しい「オフセット」(ファイルからスキップするバイト数である0に設定した数値)を使用しmunmapて、単純に自分の持っているものを使用することもできます。mmap

于 2012-05-02T19:00:18.730 に答える
2
#include <stdlib.h> /* for realloc() */
#include <string.h> /* for memcpy() */
#include <unistd.h> /* for read() */

char buff[512] ; /* anything goes */
size_t done, size;
char *result = NULL;
int fd;

done = size = 0;
while (1) {
        int n_read;
        n_read = read(fd, buff, sizeof buff);
        if (n_read <=0) {
            ... for network connections, (n_read == -1 && errno == EAGAIN)
            ... should be handled special (by a continue) here.
            break;
            }
        if (done+n_read > size) {
            result = realloc(result, size ? 2*size : n_read );
            ... maybe handle NULL return from realloc here ...
            size = size ? 2*size : n_read;
            }
        memcpy(result+done, buff, n_read);
        done += n_read;
        }
 ... and maybe shave down result a bit here ...

注: これは多かれ少なかれバニラのやり方です。もう 1 つの方法は、実際に大きな配列を最初に malloc し、後で適切なサイズに再割り当てすることです。これにより、再割り当ての数が減り、フラグメンテーションに関して、mallocアリーナにとってより穏やかになる可能性があります。YMMV。

于 2012-05-02T19:12:02.657 に答える