6

ファイルの内容をバッファに読み込むための次のコードについて考えてみます。

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define BLOCK_SIZE 4096

int main()
{
   int fd=-1;
   ssize_t bytes_read=-1;
   int i=0;
   char buff[50];
   //Arbitary size for the buffer?? How to optimise.
   //Dynamic allocation is a choice but what is the
   //right way to relate the file size to bufffer size.

   fd=open("./file-to-buff.txt",O_RDONLY);
   if(-1 == fd)
   {
      perror("Open Failed");
      return 1;
   }

   while((bytes_read=read(fd,buff,BLOCK_SIZE))>0)
   {
      printf("bytes_read=%d\n",bytes_read);
   }

   //Test to characters read from the file to buffer.The file contains "Hello"
   while(buff[i]!='\0')
   {
      printf("buff[%d]=%d\n",i,buff[i]);
      i++;
      //buff[5]=\n-How?
   }
   //buff[6]=`\0`-How?
   close(fd);
   return 0;
}

コードの説明:

  • 入力ファイルには文字列「Hello」が含まれています
  • このコンテンツをバッファにコピーする必要があります。
  • 目的は、POSIXAPIによって達成されopenますread
  • 読み取りAPIは、任意のサイズのバッファーへのポインターを使用して、データをコピーします。

質問:

  • 動的割り当ては、バッファのサイズを最適化するために使用する必要がある方法です。入力ファイルサイズからバッファサイズを関連付ける/導出するための正しい手順は何ですか?
  • 操作の最後に、読み取りで「Hello」という文字に加えてaと1つの文字readがコピーされていることがわかります。この読み取りの動作について詳しく説明してください。new line characterNULL

サンプル出力

bytes_read = 6

バフ[0]=H

buff [1] = e

バフ[2]=l

バフ[3]=l

buff [4] = o

バフ[5]=

PS:入力ファイルは、プログラムによって作成されたものではなく、ユーザーが作成したファイルです(writeAPIを使用)。それが何か違いを生む場合に備えて、ここで言及するだけです。

4

4 に答える 4

7

ファイル全体を読み取りたいので、バッファをファイルサイズと同じ大きさにするのが最善の方法です。バッファのサイズを変更しても意味がありません。それは正当な理由なしにパフォーマンスを損なうだけです。

ファイルサイズはいくつかの方法で取得できます。手っ取り早い方法はlseek()、ファイルの最後までです。

// Get size.
off_t size = lseek(fd, 0, SEEK_END); // You should check for an error return in real code
// Seek back to the beginning.
lseek(fd, 0, SEEK_SET);
// Allocate enough to hold the whole contents plus a '\0' char.
char *buff = malloc(size + 1);

もう1つの方法は、次を使用して情報を取得することfstat()です。

struct stat fileStat;
fstat(fd, &fileStat); // Don't forget to check for an error return in real code
// Allocate enough to hold the whole contents plus a '\0' char.
char *buff = malloc(fileStat.st_size + 1);

必要なすべてのタイプと関数プロトタイプを取得するには、必要なヘッダーが含まれていることを確認してください。

#include <sys/stat.h> // For fstat()
#include <unistd.h>   // For lseek()

read()でデータを自動的に終了しないことに注意してください\0。これは手動で行う必要があります。そのため、バッファに追加の文字(size + 1)を割り当てます。あなたのケースにすでにキャラクターがいる理由\0は、純粋にランダムなチャンスです。

もちろん、bufは動的に割り当てられた配列なので、不要になったときに再度解放することを忘れないでください。

free(buff);

ただし、読み込みたいファイルと同じ大きさのバッファを割り当てると危険な場合があることに注意してください。(誤ってまたは故意に、問題ではない)ファイルが数GB大きい場合を想像してみてください。このような場合は、最大許容サイズを設定しておくとよいでしょう。ただし、そのような制限が必要ない場合は、ファイルから読み取る別の方法に切り替える必要がありますmmap()。を使用mmap()すると、ファイルの一部をメモリにマップできます。そうすれば、ファイルの大きさは関係ありません。一度に作業できるのはファイルの一部だけであり、メモリ使用量を制御できるからです。

于 2012-11-10T13:58:25.217 に答える
3

1、stat(filename、&stat)でファイルサイズを取得できますが、ページサイズにバッファを定義するのは問題ありません

2、最初に、「こんにちは」の後にヌル文字はありません。コードが実行される前に割り当てたスタック領域が0であったのは偶然であるに違いありません。APUEの7.6章を参照してください。実際、ローカル変数を使用する前に初期化する必要があります。

vim、emacs、echo -n Hello> file-to-buff.txtを使用してテキストファイルを生成しようとしましたが、vimのみが自動的に改行を追加します

于 2012-11-10T15:42:33.983 に答える
2

最初に固定サイズのバッファを作成し、それを埋めるときにサイズmallocを2倍(で)にすることで、バッファを動的に割り当てることを検討できます。reallocこれには、時間の複雑さとスペースのトレードオフがあります。

現時点では、同じバッファに繰り返し読み込んでいます。読み取るたびにバッファ内のポイントを増やす必要があります。そうしないと、バッファの内容がファイルの次のセクションで上書きされます。

指定したコードはバッファに50バイトを割り当てますが、サイズとして4096をに渡しますread。これにより、50バイトを超えるファイルのバッファオーバーフローが発生する可能性があります。

`\n'と'\0'について。改行はおそらくファイルにあり、「\0」はすでにバッファにあります。バッファはコード内のスタックに割り当てられ、スタックのそのセクションがまだ使用されていない場合は、プログラムがロードされたときにオペレーティングシステムによってそこに配置されたゼロが含まれている可能性があります。

オペレーティングシステムは、ファイルから読み取られたデータを終了しようとはしません。それは、バイナリデータであるか、理解できない文字セットである可能性があります。必要に応じて、文字列を終了するのはあなた次第です。

よりスタイルの問題である他のいくつかのポイント:

  • for (i = 0; buff[i]; ++i)最後に印刷するために、しばらくではなくループを使用することを検討できます。このようにして、誰かがインデックス変数iをいじっても影響を受けません。
  • ファイルの読み取りが終了した後、ファイルを長時間開いたままにしないように、ファイルを早く閉じることができます(また、何らかのエラーが発生した場合にファイルを閉じるのを忘れる可能性があります)。
于 2012-11-10T13:15:57.903 に答える
1

2番目の質問でreadは、文字を自動的に追加しないでください'\0'。ファイルがテキストファイルであると考える場合は、'\0'呼び出し後readに文字列の終わりを示すためにafterを追加する必要があります。

Cでは、文字列の終わりはこの文字で表されます。read4文字を設定printfすると、これらの4文字を読み取り、5番目をテストします。そうでない場合は、'\0'次の文字まで印刷を続行します'\0'。バッファオーバーフローの原因にもなります

の場合、'\n'おそらく入力ファイルにあります。

于 2012-11-10T13:40:26.100 に答える