10

C コードで大きなファイル (4 ~ 8 GB) を生成しようとしています。今、私はパラメーターを使用fopen()'wb'てファイルバイナリを開き、ループでfwrite()関数を使用してバイトをファイルに書き込みます。forループの繰り返しごとに 1 バイトを書き込んでいます。ファイルが 4294967296 バイト (4096 MB) 以上になるまでは問題ありません。32 ビット OS のメモリ制限のように見えます。これは、開いているファイルに書き込むときに、まだ RAM にあるためです。私は正しいですか?症状は、作成されたファイルのサイズが必要以上に小さいことです。違いは 4096 MB です。たとえば、6000 MB のファイルが必要な場合、6000 MB - 4096 MB = 1904 MB のファイルが作成されます。

そのタスクを実行する他の方法を提案できますか?

よろしく:)

コードの一部:

unsigned long long int number_of_data = (unsigned int)atoi(argv[1])*1024*1024; //MB
char x[1]={atoi(argv[2])};

fp=fopen(strcat(argv[3],".bin"),"wb");

    for(i=0;i<number_of_data;i++) {
        fwrite(x, sizeof(x[0]), sizeof(x[0]), fp);
    }

fclose(fp);
4

3 に答える 3

2

Windows で大きなファイルを作成するのに問題はないはずですが、ファイルに対して 32 ビット バージョンのシークを使用すると、ファイルが 32 ビット ファイルであると判断され、4 GB を超えることはできないことに気付きました。Windows で 4GB を超えるファイルを操作する場合、_open、_lseeki64、および _write を使用して成功しました。例えば:

static void
create_file_simple(const TCHAR *filename, __int64 size)
{
    int omode = _O_WRONLY | _O_CREAT | _O_TRUNC;
    int fd = _topen(filename, omode, _S_IREAD | _S_IWRITE);
    _lseeki64(fd, size, SEEK_SET);
    _write(fd, "ABCD", 4);
    _close(fd);
}

上記は問題なく4GBを超えるファイルを作成します。ただし、そこで_write()を呼び出すと、ファイルシステムが実際にディスクブロックを割り当てる必要があるため、遅くなる可能性があります。ランダムにファイルを埋める必要がある場合は、スパース ファイルを作成する方が速い場合があります。ファイルを最初から順番に埋める場合、上記のコードは問題ありません。fwrite によって提供されるバッファリングされた IO を実際に使用したい場合は、fdopen() を使用して C ライブラリ ファイル記述子から FILE* を取得できることに注意してください。

(誰かが疑問に思っている場合に備えて、TCHAR、_topen、およびアンダースコアのプレフィックスはすべて MSVC++ の癖です)。

アップデート

元の質問は、値 V の N バイトの順次出力を使用することです。したがって、実際に必要なファイルを生成する単純なプログラムは次のとおりです。

#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <io.h>
#include <tchar.h>
int
_tmain(int argc, TCHAR *argv[])
{
    __int64 n = 0, r = 0, size = 0x100000000LL; /* 4GB */
    char v = 'A';
    int fd = _topen(argv[1], _O_WRONLY | _O_CREAT| _O_TRUNC, _S_IREAD | _S_IWRITE);
    while (r != -1 && n < count) {
        r = _write(fd, &v, sizeof(value));
        if (r >= 0) n += r;
    }
    _close(fd);
    return 0;
}

ただし、一度に 1 バイトしか書き込まないため、これは非常に遅くなりますこれは、より大きなバッファを使用するか、ディスクリプタ (fd) で fdopen を呼び出して fwrite に切り替えることでバッファリングされた I/O を使用することで改善できます。

于 2013-05-13T11:03:30.473 に答える
2

fwriteここでは問題ではありません。問題は、あなたが計算している値ですnumber_of_data

64 ビット整数を扱うときは、意図しない 32 ビット キャストに注意する必要があります。それらを定義するとき、私は通常、各ステップで注意しながら、いくつかの個別のステップでそれを行います。

unsigned long long int number_of_data = atoi(argv[1]); // Should be good for up to 2,147,483,647 MB (2TB)
number_of_data *= 1024*1024; // Convert to MB

代入演算子 ( *=) は左辺値 ( unsigned long long int) に作用するため、64 ビット値に作用すると信頼できます。

これは最適化されていないように見えるかもしれませんが、まともなコンパイラは不要なステップを削除します。

于 2013-05-13T13:45:03.580 に答える
1

ユオは問題ありませんfwrite()。問題はあなたのようです

unsigned long long int number_of_data = (unsigned int)atoi(argv[1])*1024*1024; //MB

これは実際にはむしろ次のようなものでなければなりません

uint16_t number_of_data = atoll(argv[1])*1024ULL*1024ULL;

unsigned long longそれでも問題unsigned int * int * intありunsinged intませんが、ターゲット変数がどれほど大きくても、

于 2013-05-13T12:29:38.437 に答える