C 通过mmap写入文件,但当我使用fread时,第二次读取错误数据

C 通过mmap写入文件,但当我使用fread时,第二次读取错误数据,c,linux,mmap,fread,C,Linux,Mmap,Fread,当我使用mmap和memcpy编写文件,然后使用fread读取数据时。 下面是我的代码,问题是我第一次能读a,但第二次不能读a。 我猜在fread函数中有类似seek位置的东西,当我使用memcpy写入文件时,它可能会改变seek位置 #include <dirent.h> #include <errno.h> #include <fcntl.h> #include <pthread.h> #include <stdio.h> #inc

当我使用mmap和memcpy编写文件,然后使用fread读取数据时。 下面是我的代码,问题是我第一次能读a,但第二次不能读a。 我猜在fread函数中有类似seek位置的东西,当我使用memcpy写入文件时,它可能会改变seek位置

#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>

int main()
{


    int fd = open("./aa", O_CREAT | O_RDWR | O_TRUNC, 0644);
    FILE* f = fopen("./aa", "r");
    if (ftruncate(fd, 1024) < 0) {
        printf("ftruncate error\n");
    }
    void* base;
    if ((base = mmap(NULL, 1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) {
        printf("mmap error\n");
    }
    char* file_ptr = (char *)base;
    char buffer[256];
    char scratch[256];
    buffer[0] = 'a';
    memcpy(file_ptr, buffer, 1);
    file_ptr += 1;
    size_t n = fread(scratch, 1, 1, f);
    printf("size n %zu\n", n); // this output size n 1
    printf("scratch %c\n", scratch[0]); // this output scratch a
    memcpy(file_ptr, buffer, 1);
    file_ptr += 1;
    n = fread(scratch, 1, 1, f);
    printf("size n %zu\n", n); // this output size n 1
    printf("scratch %c\n", scratch[0]); // but this output scratch  
    return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
int main()
{
int fd=开放(“/aa”,O|u CREAT | O|u RDWR | O|u TRUNC,0644);
文件*f=fopen(“./aa”,“r”);
如果(ftruncate(fd,1024)<0){
printf(“ftruncate错误\n”);
}
空*基;
if((base=mmap(NULL,1024,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0))==MAP_FAILED){
printf(“mmap错误\n”);
}
char*file_ptr=(char*)基;
字符缓冲区[256];
字符划痕[256];
缓冲区[0]=“a”;
memcpy(文件,缓冲区,1);
文件_ptr+=1;
尺寸n=fread(划痕,1,1,f);
printf(“大小n%zu\n”,n);//此输出大小n 1
printf(“暂存%c\n”,暂存[0]);//此输出暂存a
memcpy(文件,缓冲区,1);
文件_ptr+=1;
n=fread(划痕,1,1,f);
printf(“大小n%zu\n”,n);//此输出大小n 1
printf(“scratch%c\n”,scratch[0]);//但是这个输出scratch
返回0;
}
输出为: 大小n 1 刮擦 大小n 1
scratch

首先,@wildplasser是正确的,您的程序可能会工作,但是如果继续混合使用mmap和stdio,您需要确保通过
mmap
完成的写入操作得到提交(使用
msync()
函数),并且fread没有缓冲过时的数据(
fseek()
ing到当前位置应该起作用)

来回答您的问题:您的程序不打印“scratch”,而是打印“scratch\0”:

说真的,您要做的是通过
ftruncate()
初始化“aa”文件的大小,这与填充最多1024'\0'的缺失字节相同;你写一个“a”,然后读它;然后你读另一个字符,得到一个NUL

尝试打印scratch[0]的ascii字符,您将看到它是零;如果您仍然不确信,请尝试添加以下内容

for(i = 0; i < 6; i++)
    file_ptr[i] = "QWERTY"[i];
(i=0;i<6;i++)的

文件_ptr[i]=“QWERTY”[i];

就在第一次memcpy之前,看看会发生什么。

注意:这可能不会影响结果,但如果您打算用C语言编写代码,则不应使用
#include
。(或
#如果您的程序未使用posix线程,则包含
)fread()是缓冲I/O。请在strace下运行您的程序以查看其功能。如果运行时文件
aa
尚不存在,此程序也会出现故障-您需要测试
f
的值是否为
NULL
@6eqj5谢谢,我已更改了我的codefread())删除x个字符,将文件描述符“f”指向文件中的x个字符。下一个fread()从上一个fread停止的位置开始,除非在两个fread()之间使用fseek()将文件描述符“f”更改回文件的开头。我看到它打印了scratch W@wildplasser是对的,fread有一个缓冲区,第二次调用fread时,它将从其缓冲区读取数据,而不是直接从文件读取数据。。因此,当我更改文件时,第二次fread没有意义。