Fread () на 6 ГБ файл не удается - PullRequest
0 голосов
/ 20 июля 2010

Хорошо, я читал о fread () [который возвращает тип size_t] и видел несколько постов, касающихся больших файлов и некоторых проблем, которые были у других, - но у меня все еще есть некоторые проблемы. Эта функция передает указатель файла и long long int. Lld из main, где я использую другую функцию для получения фактического размера файла, который составляет 6448619520 байт.

char *getBuffer(FILE *fptr, long long size) {
    char *bfr;
    size_t result;

    printf("size of file in allocate buffer:  %lld\n", size);
        //size here is 6448619520


    bfr = (char*) malloc(sizeof(char) * size);
    if (bfr == NULL) {
        printf("Error, malloc failed..\n");
        exit(EXIT_FAILURE);
    }
        //positions fptr to offset location which is 0 here.
    fseek(fptr, 0, SEEK_SET);
        //read the entire input file into bfr
    result = fread(bfr, sizeof(char), size, fptr);
    printf("result = %lld\n",  (long long) result);


    if(result != size)
    {
        printf("File failed to read\n");
        exit(5);
    }
    return (bfr);

}

Я проверил его на файлах размером около 1-2 ГБ, и он работает нормально, однако, когда я тестирую его на файле 6 ГБ, в буфер ничего не зачитывается. Не обращайте внимания на другие результаты (фокусируйтесь на жирном шрифте для результатов), проблема заключается в чтении данных BFR. Вот некоторые результаты, которые я получаю.

1-й файл размером 735844352 байта (700 + МБ)

root @ redbox: / data / projects / C / stubs / # ./testrun -x 45004E00 -i /data/Helix2008R1.iso

Файл изображения: /data/Helix2008R1.iso
шестнадцатеричная строка = 45004E00
> Общий размер файла: 735844352
размер файла в буфере получения: 735844352
результат = 735844352

** Начните анализ шестнадцатеричного значения командной строки: 45004E00
Общее количество байтов в шестнадцатеричной строке: 4

Результаты поиска в шестнадцатеричной строке:
Шестнадцатеричная строка 45004E00 была найдена в расположении байта: 37441
Шестнадцатеричная строка 45004E00 была найдена в байтовом местоположении: 524768
....

Запуск # 2 для файла 6 ГБ: root @ redbox: / data / projects / C / stubs / # ./testrun -x BF1B0650 -i /data/images/sixgbimage.img

Файл изображения /data/images/sixgbimage.img
шестнадцатеричная строка = BF1B0650
Общий размер файла: 6448619520
размер файла в буфере выделения: 6448619520
результат = 0
Не удалось прочитать файл

Я до сих пор не уверен, почему это происходит с большими файлами, а не с маленькими, это проблема> 4 ГБ. Я использую следующее:

/* Support Large File Use */
#define _LARGEFILE_SOURCE 1
#define _LARGEFILE64_SOURCE 1
#define _FILE_OFFSET_BITS   64

Кстати, я использую Ubuntu 9.10 box (ядро 2.6.x). ТИА.

Ответы [ 5 ]

4 голосов
/ 20 июля 2010

Если вы просто собираетесь читать файл, а не изменять его, я предлагаю использовать mmap(2) вместо fread(3).Это должно быть намного более эффективным, хотя я не пробовал это на больших файлах.Вам нужно будет изменить мой очень упрощенный метод «найдено / не найдено», чтобы сообщать о смещениях, если вы этого хотите, но я не уверен, для чего нужен указатель.:)

#define _GNU_SOURCE
#include <string.h>

#include <fcntl.h>
#include <sys/mman.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>


int main(int argc, char* argv[]) {
    char *base, *found;
    off_t len;
    struct stat sb;
    int ret;
    int fd;
    unsigned int needle = 0x45004E00;

    ret = stat(argv[1], &sb);
    if (ret) {
            perror("stat");
            return 1;
    }

    len = sb.st_size;

    fd = open(argv[1], O_RDONLY);
    if (fd < 0) {
            perror("open");
            return 1;
    }

    base = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
    if (!base) {
            perror("mmap");
            return 1;
    }

    found = memmem(base, len, &needle, sizeof(unsigned int));
    if (found)
            printf("Found %X at %p\n", needle, found);
    else
            printf("Not found");
    return 0;
}

Некоторые тесты:

$ ./mmap ./mmap
Found 45004E00 at 0x7f8c4c13a6c0
$ ./mmap /etc/passwd
Not found
4 голосов
/ 20 июля 2010

Если это 32-битный процесс, как вы говорите, тогда size_t является 32-битным, и вы просто не можете сохранить более 4 ГБ в адресном пространстве вашего процесса (на самом деле, на практике, чуть меньшечем 3 ГБ).В этой строке:

bfr = (char*) malloc(sizeof(char) * size);

Результат умножения будет уменьшен по модулю SIZE_MAX + 1, что означает, что он будет пытаться выделить только около 2 ГБ.Аналогично, то же самое происходит с параметром size в этой строке:

result = fread(bfr, sizeof(char), size, fptr);

Если вы хотите работать с большими файлами в 32-битном процессе, у вас есть для работытолько часть из них за раз (например, прочитайте первые 100 МБ, обработайте это, прочитайте следующие 100 МБ, ...).Вы не можете прочитать весь файл за один раз - вашему процессу просто не хватает памяти для этого.

2 голосов
/ 20 июля 2010

Когда fread терпит неудачу, он устанавливает errno, чтобы указать причину сбоя.Какое значение errno после вызова fread, который возвращает ноль?

Обновление: Требуется ли прочитать весь файл одним махом?Что произойдет, если вы прочитаете в файле, скажем, 512 МБ за раз?

Согласно вашему комментарию выше, вы используете 32-разрядную ОС.В этом случае вы не сможете обрабатывать 6 ГБ за раз (например, size_t не сможет вместить такое большое количество).Однако вы должны иметь возможность считывать и обрабатывать файл небольшими порциями.

Я бы сказал, что чтение файла 6 ГБ в память, вероятно, не лучшее решение вашей проблемы даже на 64-битной ОС,Что именно вы пытаетесь сделать, что требует буферизации файла 6 ГБ?Вероятно, есть лучший способ решить проблему.

0 голосов
/ 23 июля 2010

Получив совет от всех, я разбил файл 6 ГБ на 4K-куски, проанализировал шестнадцатеричные байты и смог узнать, какие байтовые местоположения мне помогут позже, когда я вытащу MBR из раздела VMFS, который былдд вообразил.Вот быстрый и грязный способ чтения его для каждого блока:

# define DEFAULT_BLOCKSIZE 4096
...

while((bytes_read = fread(chunk, sizeof(unsigned char), sizeof(chunk), fptr)) > 0) {
    chunkptr = chunk;
    for(z = 0; z < bytes_read; z++) {
        if (*chunkptr == pattern_buffer[current_search]) {
            current_search++;
            if (current_search > (counter - 1)) {
                current_search = 0;
                printf("Hex string %s was found at starting byte location:  %lld\n",
                       hexstring, (long long int) (offsetctr-1));
                matches++;
            }
        } else {
            current_search = 0;
        }
        chunkptr++;
        //printf("[%lld]: %02X\n", offsetctr, chunk[z] & 0xff);
        offsetctr++;
    }
    master_counter += bytes_read;
}

...

и вот результаты, которые я получил ...

root@redbox:~/workspace/bytelocator/Debug# ./bytelocator -x BF1B0650 -i /data/images/sixgbimage.img 

Total size of /data/images/sixgbimage.img file:  6448619520 bytes
Parsing the hex string now: BF1B0650

Hex string BF1B0650 was found at starting byte location:  18
Hex string BF1B0650 was found at starting byte location:  193885738
Hex string BF1B0650 was found at starting byte location:  194514442
Hex string BF1B0650 was found at starting byte location:  525033370
Hex string BF1B0650 was found at starting byte location:  1696715251
Hex string BF1B0650 was found at starting byte location:  1774337550
Hex string BF1B0650 was found at starting byte location:  2758859834
Hex string BF1B0650 was found at starting byte location:  3484416018
Hex string BF1B0650 was found at starting byte location:  3909721614
Hex string BF1B0650 was found at starting byte location:  3999533674
Hex string BF1B0650 was found at starting byte location:  4018701866
Hex string BF1B0650 was found at starting byte location:  4077977098
Hex string BF1B0650 was found at starting byte location:  4098838010


Quick stats:
================
Number of bytes that have been read:  6448619520
Number of signature matches found:  13
Total number of bytes in hex string:  4
0 голосов
/ 20 июля 2010

Вы убедились, что malloc и fread на самом деле принимают правильный тип параметров? Вы можете скомпилировать с опцией -Wall и проверить, действительно ли урезаны ваши 64-битные значения. В этом случае malloc не сообщит об ошибке, но в итоге выделит гораздо меньше, чем вы просили.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...