2013-05-13 13 views
10

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

あなたは他の方法でその作業を行うことを提案できますか?

よろしく:)コードの

パート:

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); 
+0

「i」はどのように定義されていますか? – willys

+3

'strcat(argv [3]、"。bin ")'が間違っています – BLUEPIXY

+0

@willys 'i'は次のように定義されています:' unsigned long long int i = 0; ' – bLAZ

答えて

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 

は、代入演算子(*=)はL値(unsigned long long int)に作用されますので、あなたそれが64ビット値で動作することを信頼することができます。

これは最適化されていないように見えますが、まともなコンパイラは不要な手順を削除します。

+0

このソリューションは私を助けました:)それは本当にその可変値に問題でした。しかし、この質問にすべての人が答えてくれたことに感謝します。それは非常に有用で有益でした。 – bLAZ

2

あなたは何の問題もWindows上で大きなファイルを作成する必要はありませんが、私はあなたがファイルに求めるの32ビット版を使用している場合ことに気づきましたそれはそれが32ビットのファイルであると判断して、その4GBを超えることはできません。 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バイトのためのシーケンシャル出力を使用している

UPDATE

#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を使用することで改善できます。

+0

あなたのMSVC++の特徴は、MinGW(-w64)GCCでもうまくいきます。コンパイラではなく、Windows Cランタイムライブラリの癖です。 – rubenvb

+0

おそらくそれは私が探しているものですが、私は「Hello World」から遠くないので、今私が望むようにそれを使用するのは難しいです。 – bLAZ

+0

@patthoytsその機能にファイル名を付ける方法を教えてください。 – bLAZ

1

ゆうさんはfwrite()と問題ありません。問題があると思われる、あなたの実際

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

unsigned long longのようではなく、何かがまだ大丈夫だろうにする必要がありますが、unsigned int * int * intは関係なく、あなたのターゲット変数がどのように大規模なあなたにunsinged intを与えないだろう

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

+0

これは私がそのオーバーフロー警告を得る理由です。しかし、それは今私に、 'atoll'は定義されていないことを伝えます:/私は' #include < stdlib.h > 'を持っています。 – bLAZ

+1

#include を試して_strtoui64(またはTCHARタイプを使用する場合は_tcstoui64)を使用してください。 – patthoyts

+0

明日このソリューションを試してみますが、これはおそらく@Lee Nethertonソリューション(同じ問題の問題)のように役立ちます。ありがとう。 – bLAZ