2016-09-24 6 views
10

Я использую приведенный ниже код, чтобы открыть большой (5.1GB) двоичный файл в MSVC в Windows. Машина имеет много оперативной памяти. Проблема заключается в том, что длина восстанавливается как ноль. Однако, когда я изменяю путь 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 гигабайта? Проконсультируйтесь с документацией Microsoft, чтобы использовать файлы размером более 2 гигабайт. –

+2

Используйте [второй] (https://msdn.microsoft.com/en-us/library/0ys3hc0b.aspx). –

+0

Собираетесь ли вы в режиме 32 или 64 бит? Вам нужно будет убедиться, что вы компилируете в режиме 64 бит, чтобы создать буфер 5.1 ГБ. (в дополнение к проблемам 'ftell()', указанным выше комментариями) – Cornstalks

ответ

1

Тип данных long слишком мал, чтобы представить размер файла. Используйте метод stat() (или альтернативу Windows GetFileAttributes), чтобы прочитать размер файла.

+0

Мне бы очень хотелось узнать, откуда взялась идея использовать' fseek() '/' ftell() 'для получения размера файла. Он не переносится, и он не будет работать в Windows для больших файлов. Тем не менее он продолжает показывать ... –

+0

@AndrewHenle, если вы можете показать мне правильный способ чтения большого двоичного файла, так что у меня есть указатель char * на содержимое, другие могут избежать этих плохих практик. – mezamorphic

+0

@mezamorphic Нет такой вещи, как «правильный способ чтения двоичного файла». Каковы данные в файле? Как он хранится? Что вы пытаетесь с этим сделать? Я сожалел о том, что по какой-то причине 'fseek()'/'ftell()' преподается как метод для поиска размера файла, когда на самом деле он не переносимый. Он даже не работает * на всех * на одной очень популярной платформе для больших файлов. –

2

Если вы выделили 5,1 ГБ, вам лучше убедиться, что вы скомпилировали свой код в 64 бит и запустили его в 64-битной версии Windows. Ohterwhise, память address space is limited до max 3 ГБ на 32 бита Windows и 4 GB with 32 bits code on a 64 bits Windows.

Кстати, ftell() возвращает подписанный long. Вы должны проверить, что здесь нет ошибки (например, переполнение, если ОС позволяет увеличить размер файла), так что значение не равно -1.

Редактировать:

Обратите внимание, что with MSVC, long will currently be число 32 бита, даже если скомпилирован для 64 битов. Это означает, что ftell() даст вам значимый результат, если размер файла ниже 2 ГБ (потому что для знака).

Чтобы получить размер больших файлов в подписанном 64-битовом номере, вы можете использовать функцию WinAPI, не связанную с переносимой операционной системой GetFileSizeEx().

malloc() принимает size_t, который является unsigned 64 bit number. Так что с этой стороны вы в безопасности.

Альтернативой может быть использование file mapping.

Второй редактировать

Я смотрел на ваши изменения о стоимости полученных по размеру, которые отличаются от того, что я ожидал. Я мог воспроизвести ошибку в моей системе и получил размер, который не был нулевым, но это был номер, намного больший, чем файл.

Глядя на this CERT security recommendation, оказалось, что гарантии, предлагаемые стандартом для fseek() в сочетании с SEEK_END являются и недостаточна сделать это очень небезопасно подход.

Итак, давайте повторим: самым простым способом получить размер будет использование собственной функции ОС, то есть GetFileSizeEx() на Windows. Там обходной путь на 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, и у меня 32 ГБ памяти. Я ранее открывал этот файл, используя сопоставление памяти с буфером, но сейчас я не хочу использовать этот подход. – mezamorphic

+0

@mezamorphic Но вы скомпилировали для 64-битного кода (т. Е. X64 как цель в диспетчере конфигурации MSVC - это не зависит от ОС, которую вы компилируете)? – Christophe

+0

да я. ..... – mezamorphic

Смежные вопросы