C 映射一个大文件并扫描数据

C 映射一个大文件并扫描数据,c,linux,C,Linux,尝试使用mmap在大文件中搜索模式。文件很大(比物理内存大得多)。我担心的是,如果我使用文件大小作为mmap()的第二个参数,那么将没有足够的物理内存来满足系统调用。所以我使用0x1000作为长度,希望操作系统在指针移动时自动映射文件的正确部分。但是下面的代码片段给出了分段错误 有什么想法吗 #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h&

尝试使用mmap在大文件中搜索模式。文件很大(比物理内存大得多)。我担心的是,如果我使用文件大小作为mmap()的第二个参数,那么将没有足够的物理内存来满足系统调用。所以我使用0x1000作为长度,希望操作系统在指针移动时自动映射文件的正确部分。但是下面的代码片段给出了分段错误

有什么想法吗

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

long fileSize(char *fname) {
    struct stat stat_buf;
    int rc = stat(fname, &stat_buf);
    return rc == 0 ? stat_buf.st_size : -1;
}
int main(int argc, char *argv[]) {
    long size = fileSize(argv[1]);
    printf("size=%ld\n", size);
    int fd = open(argv[1], O_RDONLY);
    printf("fd=%d\n", fd);
    char *p = mmap(0, 0x1000, PROT_READ, MAP_SHARED, fd, 0);
    if (p == MAP_FAILED) {
        perror ("mmap");
        return 1;
    }
    long i;
    int pktLen;
    int *pInt;
    for (i=0; i < size; i+=4) {
        pInt = (int*)(p+i);
        if (pInt[i] == 0x12345678) {
            printf("found it at %ld\n", i); break;
        }
    }
    if (i == size) {
        printf("didn't find it\n");
    }
    close(fd);
    return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
长文件大小(char*fname){
结构统计;
int rc=stat(fname和stat_buf);
返回rc==0?统计数据大小:-1;
}
int main(int argc,char*argv[]){
long size=fileSize(argv[1]);
printf(“大小=%ld\n”,大小);
int fd=打开(argv[1],仅限Ordu);
printf(“fd=%d\n”,fd);
char*p=mmap(0,0x1000,保护读取,映射共享,fd,0);
如果(p==映射_失败){
佩罗尔(“mmap”);
返回1;
}
龙我;
int pktLen;
整数*品脱;
对于(i=0;i
更新 原来我有一只愚蠢的虫子

线路
if(pInt[i]==0x12345678)
应该是
if(pInt[0]==0x12345678)

SIGSEGV
是因为您访问的字节超过了
0x1000
字节(在
for
循环中)。您必须
mmap()
完成
fd
size
字节

虚拟内存子系统中的按需分页的概念有助于实现与您完全相同的场景—应用程序/应用程序数据大于物理内存大小。在
mmap()
之后,当您访问(虚拟)地址时,如果没有物理页面映射到它(页面错误),内核将找到可以使用的物理页面(页面替换

或者,您可以在
mmap()/munmap()
周围放置一个循环,以
PAGE\u SIZE
PAGE\u SIZE
的倍数扫描文件。
mmap()-offset
的最后一个参数将很方便

从手册页:

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
int munmap(void *addr, size_t length);  
伪代码:

fd = open(argv[1], O_RDONLY);

last_block_size = file_size % PAGE_SIZE;
num_pages = file_size / PAGE_SIZE + (last_block_size ? 1 : 0)

for (int i = 0; i < num_pages; i++) {
    block_size = last_block_size && (i == num_pages - 1) ? last_block_size : PAGE_SIZE;

    ptr = mmap(NULL, block_size, PROT_READ, MAP_PRIVATE, fd, i * PAGE_SIZE);

    /* Consume the file's data range (ptr, ptr+block_size-1) as needed */

    munmap(ptr, block_size);
}
fd=open(argv[1],仅限ordu);
最后一块大小=文件大小%页面大小;
页面数=文件大小/页面大小+(最后一个块大小?1:0)
对于(int i=0;i
请使用
映射\u PRIVATE
,因为映射可能仅用于您的流程。它只是避免了内核为
MAP\u共享
执行一些额外的步骤

fd = open(argv[1], O_RDONLY);

ptr = mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, fd, 0);

/* Consume the entire file's data as needed */

munmap(ptr, file_size);  

编辑:它应该是
MAP\u PRIVATE
而不是
MAP\u ANON
。更改。

SIGSEGV
是因为您访问的字节超过了
0x1000
字节(在
for
循环中)。您必须
mmap()
完成
fd
size
字节

虚拟内存子系统中的按需分页的概念有助于实现与您完全相同的场景—应用程序/应用程序数据大于物理内存大小。在
mmap()
之后,当您访问(虚拟)地址时,如果没有物理页面映射到它(页面错误),内核将找到可以使用的物理页面(页面替换

或者,您可以在
mmap()/munmap()
周围放置一个循环,以
PAGE\u SIZE
PAGE\u SIZE
的倍数扫描文件。
mmap()-offset
的最后一个参数将很方便

从手册页:

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
int munmap(void *addr, size_t length);  
伪代码:

fd = open(argv[1], O_RDONLY);

last_block_size = file_size % PAGE_SIZE;
num_pages = file_size / PAGE_SIZE + (last_block_size ? 1 : 0)

for (int i = 0; i < num_pages; i++) {
    block_size = last_block_size && (i == num_pages - 1) ? last_block_size : PAGE_SIZE;

    ptr = mmap(NULL, block_size, PROT_READ, MAP_PRIVATE, fd, i * PAGE_SIZE);

    /* Consume the file's data range (ptr, ptr+block_size-1) as needed */

    munmap(ptr, block_size);
}
fd=open(argv[1],仅限ordu);
最后一块大小=文件大小%页面大小;
页面数=文件大小/页面大小+(最后一个块大小?1:0)
对于(int i=0;i
请使用
映射\u PRIVATE
,因为映射可能仅用于您的流程。它只是避免了内核为
MAP\u共享
执行一些额外的步骤

fd = open(argv[1], O_RDONLY);

ptr = mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, fd, 0);

/* Consume the entire file's data as needed */

munmap(ptr, file_size);  
编辑:它应该是
MAP\u PRIVATE
而不是
MAP\u ANON
。已更改。

使用

    struct stat  info;
    long         page;
    const char  *map;
    size_t       size, mapping;
    int          fd, result;

    page = sysconf(_SC_PAGESIZE);
    if (page < 1L) {
        fprintf(stderr, "Invalid page size.\n");
        exit(EXIT_FAILURE);
    }

    fd = open(filename, O_RDONLY);
    if (fd == -1) {
        fprintf(stderr, "%s: Cannot open file: %s.\n", filename, strerror(errno));
        exit(EXIT_FAILURE);
    }

    result = fstat(fd, &info);
    if (result == -1) {
        fprintf(stderr, "%s: Cannot get file information: %s.\n", filename, strerror(errno));
        close(fd);
        exit(EXIT_FAILURE);
    }

    if (info.st_size <= 0) {
        fprintf(stderr, "%s: No data.\n", filename);
        close(fd);
        exit(EXIT_FAILURE);
    }
    size = info.st_size;
    if ((off_t)size != info.st_size) {
        fprintf(stderr, "%s: File is too large to map.\n", filename);
        close(fd);
        exit(EXIT_FAILURE);
    }
    /* mapping is size rounded up to a multiple of page. */
    if (size % (size_t)page)
        mapping = size + page - (size % (size_t)page);
    else
        mapping = size;

    map = mmap(NULL, mapping, PROT_READ, MAP_SHARED | MAP_NORESERVE, fd, 0);
    if (map == MAP_FAILED) {
        fprintf(stderr, "%s: Cannot map file: %s.\n", filename, strerror(errno));
        close(fd);
        exit(EXIT_FAILURE);
    }

    if (close(fd)) {
        fprintf(stderr, "%s: Unexpected error closing file descriptor.\n", filename);
        exit(EXIT_FAILURE);
    }

    /*
     * Use map[0] to map[size-1], but remember that it is not a string,
     * and that there is no trailing '\0' at map[size].
     *
     * Accessing map[size] to map[mapping-1] is not allowed, and may
     * generate a SIGBUS signal (and kill the process).
    */

    /* The mapping is automatically torn down when the process exits,
     * but you can also unmap it with */
    munmap(map, mapping);
struct stat info;
长页;
常量字符*映射;
大小\u t大小,映射;
int-fd,结果;
page=sysconf(_SC_PAGESIZE);
如果(第<1L页){
fprintf(stderr,“无效的页面大小。\n”);
退出(退出失败);
}
fd=打开(仅文件名);
如果(fd==-1){
fprintf(stderr,“%s:无法打开文件:%s。\n”,文件名,strerror(errno));
退出(退出失败);
}
结果=fstat(fd和info);
if(结果==-1){
fprintf(stderr,“%s:无法获取文件信息:%s。\n”,文件名,strerror(errno));
关闭(fd);
退出(退出失败);
}
如果(info.st_size使用

struct stat info;
长页;
常量字符*映射;
大小\u t大小,映射;
int-fd,结果;
page=sysconf(_SC_PAGESIZE);
如果(第<1L页){
fprintf(stderr,“无效的页面大小。\n”);
退出(退出失败);
}
fd=打开(仅文件名);
如果(fd==-1){
fprintf(stderr,“%s:无法打开文件:%s。\n”,文件名