是否可以使用 mmap 仅映射文件的一部分?

发布于 2024-10-04 14:48:15 字数 2398 浏览 7 评论 0原文

我有一个输入文件,它有一个像这样的标题:

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

然后将一个结构体,像素*,写入该文件,该文件将被映射。

因此,我想跳过标头并使 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* ,另一个等于该 + 偏移量。

主要
c 函数
标题
makefile

I have a input file which has a header like this:

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

and then a struct is writen, pixel*, into this file, which is going to be mapped.

So, I want to skip the header and make my mmap function return the ptr to that structure. How can I do this? with lseek perhaps? Could you please exemplify?

I will leave part of my code here:

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);
    }

As you see, right now my ppm image is mapped to char* data, but I want to skip the header and map just to the pixel* part.

Here's my code with the suggestion of using 2 pointers, a char* from mmap and another one equals that + offset.

main
c functions
header
makefile

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

把梦留给海 2024-10-11 14:48:15

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

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

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

If you read the man page for mmap, you wil find that its final parameter is off_t offset. The description:

... continuing or at most 'len' bytes to be mapped from the object described by 'fd', starting at byte offset 'offset'.

I suspect if you pass your offset in as that parameter, it will do what you want.

梦屿孤独相伴 2024-10-11 14:48:15

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

You can't if the amount you need to skip is less than the system page size, since offset must be a multiple of the page size on some systems.

傾旎 2024-10-11 14:48:15

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

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

其中 offset 是文件中所需数据的偏移量。

You just need to keep 2 pointers - the pointer to the start of the mmap'd block, and the pointer to the start of the data you want inside there. As in:

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

where offset is the offset in the file to the data you want.

稍尽春風 2024-10-11 14:48:15

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

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*

如果可以,我应该注意什么?例如,就像伊格纳西奥·巴斯克斯·艾布拉姆斯所说

So, from what I understand, can I do something like this?

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);
    }

and, from that, I could map my file to whatever type I want, in this case the pixel*

If this is ok, what cautions should I take? For example, like those Ignacio Vazquez-Abrams said

雪化雨蝶 2024-10-11 14:48:15

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

Um, you did notice the 'offset' parameter that you are supplying with a zero? Assuming you know the absolute offset of what you want, you pass it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文