【问题标题】:Is it possible to map just part of a file using mmap?是否可以使用 mmap 仅映射文件的一部分?
【发布时间】:2011-05-14 20:24:38
【问题描述】:

我有一个输入文件,其标题如下:

P6\n
width\n
height\n
depth\n

然后在这个文件中写入一个结构,pixel*,该文件将被映射。

所以,我想跳过标题并让我的 mmap 函数将 ptr 返回到该结构。我怎样才能做到这一点? lseek 也许?可以举个例子吗?

我将在此处保留部分代码:

printf("Saving header to output file\n");
    if (writeImageHeader(h, fpout) == -1) {
        printf("Could not write to output file\n");
        return -1;
    }

    last_index = (int)ftell(fpout);
    //printf("offset after header= %d\n",last_index);

    //alloc mem space for one row (width * size of one pixel struct)
    row = malloc(h->width * sizeof (pixel));

    /*Create a copy of the original image to the output file, which will be inverted*/
    printf("Starting work\n");
    for (i = 0; i < h->height; i++) {
        printf("Reading row... ");
        if (getImageRow(h->width, row, fpin) == -1) {
            printf("Error while reading row\n");
        }
        printf("Got row %d || ", (i + 1));

        printf("Saving row... ");
        if (writeRow(h->width, row, fpout) == -1) {
            printf("Error while reading row\n");
        }
        printf("Done\n");
    }


    /*Open file descriptor of the ouput file.
     * O_RDWR -  Read and Write operations both permitted
     * O_CREAT - Create file if it doesn't already exist
     * O_TRUNC - Delete existing contents of file*/
    if ((fdout = open(argv[2], O_RDWR, FILE_MODE)) < 0) {
        fprintf(stderr, "Can't create %s for writing\n", argv[2]);
        exit(1);
    }

    /*Get size of the output file*/
    if (fstat(fdout, &sbuf) == -1) {
        perror("Stat error ---------->\n");
        exit(1);
    }
    //printf("Size of output file: %d\n",(int)sbuf.st_size);

    /*Maps output file to memory*/
    if ((data = mmap((caddr_t) 0, sbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fdout, 0)) == (caddr_t) (-1)) {
        perror("Error mmaping");
        exit(EXIT_FAILURE);
    }

如您所见,现在我的 ppm 图像映射到 char* 数据,但我想跳过标题并仅映射到 pixel* 部分。

这是我的代码,建议使用 2 个指针,一个来自 mmap 的 char*,另一个等于 + offset。

main
c functions
header
makefile

【问题讨论】:

  • 为什么不只使用一点指针算法和一个指针变量?
  • 请注意,caddr_t 是 ANSI C 之前的旧式废话。mmap 使用的类型是 void *
  • @R..:那么我怎样才能以正确的方式调用 mmap?这是来自一个老师的例子,lol
  • 你可以在这里找到mmap的正确原型和用法:opengroup.org/onlinepubs/9699919799/functions/mmap.html 如果你的老师试图“纠正”你并坚持写caddr_t废话,这可能会很有用。

标签: c memory pointers memory-management memory-mapped-files


【解决方案1】:

嗯,您确实注意到您提供的“偏移”参数为零?假设你知道你想要的绝对偏移量,你就通过它。

【讨论】:

    【解决方案2】:

    如果您阅读mmap 的手册页,您会发现它的最终参数是off_t offset。说明:

    ...从 'fd' 描述的对象继续或最多映射 'len' 个字节,从字节偏移量 'offset' 开始。

    我怀疑如果您将偏移量作为该参数传递,它将执行您想要的操作。

    【讨论】:

    • 除非 offset 是 4096 的倍数(或任何机器的页面大小),否则不会。
    【解决方案3】:

    如果您需要跳过的数量小于系统页面大小,则不能,因为offset 在某些系统上必须是页面大小的倍数。

    【讨论】:

    • 至少在我的系统上显示If offset or len is not a multiple of the pagesize, the mapped region may extend past the specified range. 这意味着它应该可以工作,但它当然值得检查。
    • @Steven:这里写着offset must be a multiple of the page size as returned by sysconf(_SC_PAGE_SIZE).
    • 猜猜我的 mmap 比你的更棒:-p 我希望更好地记录这种不兼容性。
    • @Steven:mmap 实现没有什么“令人敬畏”的,它默默地无法共享实际的缓存页面。这可能会导致各种同步错误/竞争条件,并且至少会浪费大量内存。
    • @R.:我当时(我想!)显然是在开玩笑。我希望如果性能降低,它会被记录在案,但并不是所有的希望都能实现......
    【解决方案4】:

    那么,据我了解,我可以这样做吗?

    off_t offset_after_header = lseek(fdout, last_index, SEEK_SET);
        printf("Pointer is on %d\n",(int)offset_after_header);
        /*Maps output file to memory*/
        if ((data = mmap((caddr_t) 0, sbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fdout, offset_after_header)) == (caddr_t) (-1)) {
            perror("Error mmaping");
            exit(EXIT_FAILURE);
        }
    

    然后,我可以将我的文件映射到我想要的任何类型,在本例中为pixel*

    如果没问题,我应该注意什么?例如,就像 Ignacio Vazquez-Abrams 所说的那样

    【讨论】:

      【解决方案5】:

      您只需要保留 2 个指针 - 指向 mmap'd 块的开头的指针,以及指向您想要在其中的数据的开头的指针。如:

      unsigned char *block = mmap(0, sbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fdout, 0);
      unsigned char *data = block + offset;
      

      其中offset 是文件中您想要的数据的偏移量。

      【讨论】:

      • 您能举个例子吗?我不明白......这个时间太长了。抱歉
      • 该数据是映射的实际部分吗?我可以使用 pixel* 而不是 char* 对吗?
      • 您确实需要将初始指针算术作为char 指针进行,因为偏移量将以字节为单位,而不是更大的类型。获得数据指针后,您可以将其转换为其他任何内容(只要它为访问该类型而适当对齐)。
      • 嗯,好的。我不知道。我试过了,我的图像倒置了,但左侧仍然有垃圾……该死!如果你们中的一些人可以看到并尝试,我会留下我当前的代码...拜托?
      猜你喜欢
      • 2017-01-20
      • 2012-03-16
      • 1970-01-01
      • 2017-09-02
      • 2023-03-06
      • 2014-09-30
      • 1970-01-01
      • 1970-01-01
      • 2013-06-14
      相关资源
      最近更新 更多