2016-12-16 5 views
1

я открываю огромный файл (11GB), MMAP его Memmory, и не искать строку в файлеstrstr на огромном mmapped файле

мой код

if ((fd = open("l", O_RDONLY)) < 0)  err_sys("Cant open file"); 
if (fstat(fd, &statbuf) < 0)    err_sys("Cant get file size"); 
printf("size is %ld\n", statbuf.st_size); 

if ((src = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) err_sys("Cant mmap"); 
printf("src pointer is at %ld\n", src); 

char * index = strstr(src, "bin/bash"); 
printf("needle is at %ld\n", index); 

Он работает на маленьких файлах, но на огромные источники возвращает 0. Какую функцию я должен использовать для поиска в огромных mmapped-файлах?

Выход:

size is 11111745740 
src pointer is at 140357526544384 
needle is at 0 
+0

Вы уверены, что файл содержит '«бен/Баш»' вообще? – EOF

+2

Вы компилируете свою программу в виде 32-битной программы? Вы включили поддержку большого файла? Для какой операционной системы вы программируете? Что означает «провал»? Если один из системных вызовов не удался, каково было значение 'errno' впоследствии? Пожалуйста, предоставьте нам эту информацию. – fuz

+0

Кроме того, '% ld' не является правильным спецификатором форматирования для печати указателя, и это также не для' off_t'. – fuz

ответ

3

Вы не должны использовать strstr() для поиска текста в памяти отображенного файла:

  • Если файл является двоичным, то, скорее всего, содержит нулевые байты, которые будут прекратите поиск слишком рано. Это, вероятно, то, что вы наблюдаете.
  • Если файл является чистым текстом, но не содержит соответствия, strstr будет продолжать сканирование за пределами конца файла, вызывая неопределенное поведение, пытаясь прочитать неразмещенную память.

Вы могли бы вместо того, чтобы использовать функцию с эквивалентной семантикой, но применяется к необработанным памяти вместо строк C, memmem(), доступных на Linux и BSD систем:

void *memmem(const void *p1, size_t size1, const void *p2, size_t size2); 

Обратите внимание, что вы также можете использовать неправильные printf форматы : она должна быть %p для src и index, и вы могли бы предпочесть печать смещение как ptrdiff_t или unsigned long long:

if ((fd = open("l", O_RDONLY)) < 0) 
     err_sys("Cannot open file"); 
    if (fstat(fd, &statbuf) < 0) 
     err_sys("Cannot get file size"); 

    printf("size is %llu\n", (unsigned long long)statbuf.st_size); 

    if ((src = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) 
     err_sys("Cannot mmap"); 

    printf("src pointer is at %p\n", (void*)src); 

    char *index = memmem(src, statbuf.st_size, "bin/bash", strlen("bin/bash")); 
    printf("needle is at %p\n", (void*)index); 

    if (index != NULL) 
     printf("needle is at offset %llu\n", (unsigned long long)(index - src)); 

Если memmem не доступна на вашей платформе, вот простая реализация:

#include <string.h> 

void *memmem(const void *haystack, size_t n1, const void *needle, size_t n2) { 
    const unsigned char *p1 = haystack; 
    const unsigned char *p2 = needle; 

    if (n2 == 0) 
     return (void*)p1; 
    if (n2 > n1) 
     return NULL; 

    const unsigned char *p3 = p1 + n1 - n2 + 1; 
    for (const unsigned char *p = p1; (p = memchr(p, *p2, p3 - p)) != NULL; p++) { 
     if (!memcmp(p, p2, n2)) 
      return (void*)p; 
    } 

    return NULL; 
}  
+0

Вы ищете функцию Linux и BSD ['memmem()'] (http://man7.org/linux/man-pages/man3/memmem.3.html)? Он не указан в POSIX и не отображается в Windows. –

+0

@JonathanLeffler: действительно, эта функция доступна для некоторых, но не для всех Unix-систем. В стандарте C есть 'memchr()', 'memcpy()', 'memcmp()', 'memmove()' ...было бы целесообразно включить 'memmem()' и некоторые другие полезные функции Posix, такие как 'strdup()', 'getline()' и т. д. – chqrlie

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