2012-05-02 28 views
2

私はこのコードで目のセット(またはそれ以上)を使うことができました。私は、ファイルストリーム(f1)から配列/バッファ(ファイルはテキストファイル、配列はchar型)のバイト量を読み込みようとしています。私が "buffer - 1"の大きさで読み込んだ場合、配列を "realloc"し、読み終わったところから読み込みを続けます。基本的に私は、不明なサイズのファイルのバッファを動的に拡張しようとしています。私が不思議なこと:Cでmallocを使ってテキストファイルを配列に読み込む

  1. 私はこれを間違って実装していますか?
  2. 「realloc」のようなものでエラー状態を確認する方法 コードと同じですか?
  3. 「組み込み関数reallocの暗黙の宣言」についてコンパイルすると、多くの警告が出ます(read、malloc、strlenなどの使用についての警告が表示されています)。
  4. "read()" getが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; 
} 

私はダイナムのこのタイプを行う方法を学んでいたよう私は誰かがこの種のことでベストプラクティスについての簡単な事実を述べることができるかどうか疑問に思っています。私はこれが専門家の世界でTON(サイズが不明なファイルを読む)が来ると仮定していますか?御時間ありがとうございます。 ALSO:あなたが物事を行う良い方法(つまり、この種の問題のテクニック)を見つけたら、あなたがそれをどうやって記憶しているのか、それとも将来的に参照するために保存しているのでしょうか?

+0

あなたはread()を2回呼び出しています。繰り返さないでください。 – wildplasser

+1

あなたはread()を2回呼び出しています。繰り返さないでください –

答えて

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の使用を検討してください。

2

ここではクールなトリックです:mmap(man mmap)を代わりに使用してください。

つまり、ファイルディスクリプタ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を呼び出して、あなたの現在のマッピングから読み出され、サイズを大きくするためにmremapを使用することができます。または、単にmunmapあなたが持っている、とmmap新しい "オフセット"(私は0に設定されている番号は、ファイルから何バイトをスキップする)です。

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し、あとで正しいサイズにreallocすることです。これにより、reallocの数が減ります。は、mallocアリーナ、wrtフラグメンテーションでより穏やかになる可能性があります。 YMMV。

関連する問題