2016-09-24 11 views
10

私は以下のコードを使用して、Windows上のMSVCで大きな(5.1GB)バイナリファイルを開きます。マシンにはたくさんのRAMがあります。問題は、長さがゼロとして取得されていることです。しかし、file_pathをより小さなASCIIファイルに変更すると、コードは正常に動作します。小さなバイナリファイルではなく、小さなASCIIファイルを開くことができますか?

大きなバイナリファイルを読み込めないのはなぜですか?私はファイルの内容へのポインタを必要としたので、このアプローチを好む。

FILE * pFile; 
uint64_t lSize; 
char * buffer; 
size_t result; 

pFile = fopen(file_path, "rb"); 
if (pFile == NULL) { 
    fputs("File error", stderr); exit(1); 
} 

// obtain file size: 
fseek(pFile, 0, SEEK_END); 
lSize = ftell(pFile);        // RETURNS ZERO 
rewind(pFile); 

// allocate memory to contain the whole file: 
buffer = (char*)malloc(sizeof(char)*lSize); 
if (buffer == NULL) { 
    fputs("Memory error", stderr); exit(2); 
} 

// copy the file into the buffer: 
result = fread(buffer, 1, lSize, pFile);    // RETURNS ZERO TOO 
if (result != lSize) {        // THIS FAILS 
    fputs("Reading error", stderr); exit(3); 
} 

/* the whole file is now loaded in the memory buffer. */ 

ファイルのパーミッションでもなくても、それは問題ありません。

+7

'ftell()'によって返される値が4バイトの整数で、 'long'もそうである場合、この値がどのように2ギガバイトを超える数値を表すと思いますか?サイズが2ギガバイトを超えるファイルを使用する適切な方法については、Microsoftのマニュアルを参照してください。 –

+2

[2番目のもの](https://msdn.microsoft.com/en-us/library/0ys3hc0b.aspx)を使用してください。 –

+0

32ビットまたは64ビットモードでコンパイルしていますか? 5.1GBのバッファを作成するには、64ビットモードでコンパイルしていることを確認する必要があります。 (上のコメントで指摘されている 'ftell()'の問題に加えて) – Cornstalks

答えて

1

データ型がlongでファイルサイズを表すには小さすぎます。ファイルサイズを読み取るには、stat()メソッド(またはWindows固有の代替GetFileAttributes)を使用します。

+0

ファイルのサイズを取得するために' fseek() '/' ftell() 'を使う考え方がどこから来るのか本当に知りたいです。ポータブルではないため、大きなファイルの場合はWindowsでは動作しません。しかし、それが表示され続ける... –

+0

@AndrewHenle私は大きなバイナリファイルを読み取る正しい方法を示すことができるので、私はコンテンツへのchar *ポインタを持っている、他の人はこれらの悪い習慣を避けることができます。 – mezamorphic

+0

@mezamorphic "バイナリファイルを読む正しい方法"はありません。ファイル内のデータは何ですか?それはどのように保存されますか?あなたはそれで何をしようとしていますか?私は何らかの理由で 'fseek()'/'ftell()'がファイルのサイズを見つける方法として教えられるということを嘆いていました。実際には移植性がありません。大規模なファイルのための非常に一般的なプラットフォームでは、*全く動作しません。 –

2

5,1 GBを割り当てる場合は、コードを64ビットでコンパイルして、64ビットのWindowsバージョンで実行することをお勧めします。 Ohterwhise、メモリはaddress space is limited〜32ビットWindowsでは最大3GB、4 GB with 32 bits code on a 64 bits Windowsです。

ところで、ftell()は、longという符号を返します。ここでエラーがないことを確認する必要があります(OSのサイズが大きい場合はオーバーフローなど)。その値は-1ではありません。

編集:

注64ビット用にコンパイルされた場合でも、32ビット数with MSVC, long will currently beこと。つまり、ftell()は、ファイルサイズが2GB未満の場合(意味があるため)、意味のある結果をもたらします。

非ポータブルOS固有のWinAPI関数GetFileSizeEx()を使用すると、大きなファイルのサイズを符号付き64ビット数で取得できます。

malloc()は、であるsize_tをとります。だからこそあなたは安全です。

代わりにfile mappingを使用することもできます。

第二編集

私は私が期待したものとは異なる大きさのために受け取った値について、編集内容、見ました。私は自分のシステム上でエラーを再現することができ、ヌルではないサイズを取得しましたが、ファイルよりはるかに大きな数値でした。

SEEK_ENDと組み合わせてfseek()の標準で提供される保証は不十分であり、これは非常に安全ではありません。

だから、サイズを取得する最も賢明な方法は、ネイティブOSの機能(WindowsではGetFileSizeEx())を使用することです。 64ビットWindows上での回避策があります:_fseeki64()_ftelli64()を使用します。

... 
if (_fseeki64(pFile, 0, SEEK_END)) { 
    fputs("File seek error", stderr); 
    return (1); 
} 
lSize = _ftelli64(pFile);       // RETURNS EXACT SIZE 
... 

これは(最初の問題の大きさが十分ではなかった戻り値の型とリンクしているように見えた)非常によく働きました。ただし、これは回避策であり、CERTによって報告された脆弱性を引き起こす可能性のあるその他のエラー状態が存在する可能性があることを念頭に置いてください。

+0

これはWindows 7 64です。私は32GBのメモリを持っています。私は以前にブーストメモリマッピングを使ってこのファイルを開いていましたが、私は今このアプローチを使用したくありません。 – mezamorphic

+0

@ mezamorphicしかし、64ビットコード(つまり、x64をMSVC構成マネージャーのターゲットとしてコンパイルしましたか?これはコンパイルしているOSとは関係ありません)ですか? – Christophe

+0

はい私はしました。 ..... – mezamorphic

関連する問題