0

私は非常に大きなユーザー生成入力ファイルを処理するアプリケーションを書いています。プログラムはファイルの約95%をコピーし、ファイルを効果的に複製し、コピー内のいくつかの単語と値を切り替えてから、各ブロック(10〜50で構成される)が元のファイルに(チャンクで)コピーを追加します。元の行の後には、コピーおよび変更されたブロックが続き、次の元のブロックが続きます。ユーザーが生成した入力は特定の形式に準拠しており、元のファイルの行が100文字を超える可能性はほとんどありません。

どちらがより良いアプローチでしょうか?

  1. 1つのファイルポインタを使用し、読み取られた量と書き込み先の現在の位置を保持する変数を使用して、ファイルポインタを前後に検索して読み取りと書き込みを行います。また

  2. 複数のファイルポインタを使用するには、1つは読み取り用、もう1つは書き込み用です。

入力ファイルは最大25,000行に達し、それぞれの長さは約50文字になるため、私は主にプログラムの効率に関心を持っています。

4

2 に答える 2

4

メモリに制約がある場合、または一般的なアプローチが必要な場合は、1つのファイルポインタからバッファにバイトを読み込み、変更を加え、バッファがいっぱいになったときにバッファを2番目のファイルポインタに書き込みます。最初のポインターでEOFに達した場合は、変更を加えて、バッファー内にあるものをすべて出力ポインターにフラッシュします。元のファイルを置き換える場合は、出力ファイルを入力ファイルにコピーして、出力ファイルを削除します。この「アトミック」アプローチでは、何かを削除する前に、コピー操作が正しく行われたことを確認できます。

たとえば、任意の数のバイト、たとえば一度に1MiBを一般的にコピーする場合は次のようになります。

#define COPY_BUFFER_MAXSIZE 1048576

/* ... */

unsigned char *buffer = NULL;
buffer = malloc(COPY_BUFFER_MAXSIZE);
if (!buffer)
    exit(-1);

FILE *inFp = fopen(inFilename, "r");
fseek(inFp, 0, SEEK_END);
uint64_t fileSize = ftell(inFp);
rewind(inFp);

FILE *outFp = stdout; /* change this if you don't want to write to standard output */

uint64_t outFileSizeCounter = fileSize; 

/* we fread() bytes from inFp in COPY_BUFFER_MAXSIZE increments, until there is nothing left to fread() */

do {
    if (outFileSizeCounter > COPY_BUFFER_MAXSIZE) {
        fread(buffer, 1, (size_t) COPY_BUFFER_MAXSIZE, inFp);
        /* -- make changes to buffer contents at this stage
           -- if you resize the buffer, then copy the buffer and 
              change the following statement to fwrite() the number of 
              bytes in the copy of the buffer */
        fwrite(buffer, 1, (size_t) COPY_BUFFER_MAXSIZE, outFp);
        outFileSizeCounter -= COPY_BUFFER_MAXSIZE;
    }
    else {
        fread(buffer, 1, (size_t) outFileSizeCounter, inFp);
        /* -- make changes to buffer contents at this stage
           -- again, make a copy of buffer if it needs resizing, 
              and adjust the fwrite() statement to change the number 
              of bytes that need writing */
        fwrite(buffer, 1, (size_t) outFileSizeCounter, outFp);
        outFileSizeCounter = 0ULL;
    }
} while (outFileSizeCounter > 0);

free(buffer);

サイズ変更されたバッファを処理する効率的な方法は、2番目のポインタを保持することです。たとえば、unsigned char *copyBuffer蓄積realloc()された編集を処理するために、必要に応じて2倍のサイズに変更されます。そうすれば、高額なrealloc()通話を最小限に抑えることができます。

なぜこれが反対票を投じられたのかはわかりませんが、一般的な量のデータで物事を行うためのかなり堅実なアプローチです。いずれにせよ、これがこの質問に出くわした人に役立つことを願っています。

于 2012-11-21T17:52:10.407 に答える
1

25000行*100文字=2.5MB、これは実際には大きなファイルではありません。最も速いのは、おそらくメモリ内のファイル全体を読み取り、結果を新しいファイルに書き込んで、元のファイルをそのファイルに置き換えることです。

于 2012-11-21T17:03:40.403 に答える