メモリに制約がある場合、または一般的なアプローチが必要な場合は、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()
通話を最小限に抑えることができます。
なぜこれが反対票を投じられたのかはわかりませんが、一般的な量のデータで物事を行うためのかなり堅実なアプローチです。いずれにせよ、これがこの質問に出くわした人に役立つことを願っています。