在使用内存映射操作文件之前,我们先按照常规的方式来读写文件,这种方式操作如下:
1,打开或创建文件,得到文件描述符,
2,将内存中的数据以一定的格式和顺序写入文件,或者将文件中的数据以一定的格式和顺序读入到内存;
3,关闭文件描述符;
下边是按照常规方式操作固定格式的文件的方法,包含读写两个示例;
-
-
-
-
-
-
//写内存到文件
-
struct student{
-
char name[ 20];
-
short age;
-
float score;
-
char sex;
-
};
-
int main()
-
{
-
struct student stu[5];
-
mode_t mode;
-
mode=umask( 000);
-
int fd=open( "user.dat",O_RDWR|O_CREAT|O_EXCL, 00666);
-
if(fd== -1){
-
printf( "open:%m\n");
-
umask(mode);
-
exit( -1);
-
}
-
printf( "ok\n");
-
memset(stu, 0, sizeof(stu));
-
int i= 0;
-
for(;i< 5;i++){
-
memcpy(stu[i].name, "tom", strlen( "tom")+ 1);
-
stu[i].age=i;
-
stu[i].score= 89.12f;
-
stu[i].sex= 'm';
-
write(fd,&stu[i], sizeof(stu[i]));
-
}
-
close(fd);
-
umask(mode);
-
return 0;
-
}
-
-
-
-
-
-
-
typedef struct{
-
char name[ 20];
-
short age;
-
float score;
-
char sex;
-
}Student;
-
//读取文件到内存
-
int main()
-
{
-
Student stu[ 5];
-
mode_t mode;
-
mode=umask( 0000);
-
int fd=open( "user.dat",O_RDWR, 0666);
-
if(fd== -1){
-
printf( "open:%m\n");
-
umask(mode);
-
exit( -1);
-
}
-
printf( "open ok! can read;\n");
-
int i= 0;
-
for(;i< 5;i++){
-
read(fd,&stu[i], sizeof(stu[i]));
-
}
-
close(fd);
-
i= 0;
-
for(;i< 5;i++){
-
printf( "stu[%d].name=%s\n",i,stu[i].name);
-
printf( "stu[%d].age=%d\n",i,stu[i].age);
-
printf( "stu[%d].sex=%c\n",i,stu[i].sex);
-
printf( "stu[%d].score=%f\n",i,stu[i].score);
-
}
-
umask(mode);
-
return 0;
-
}
以上操作文件的方式只能操作小文件,如果文件很大,就无法一次载入内存操作,我们就需要用到内存映射技术来操作;具体实现如下:
1,首先打开文件,使用的函数原型如下:
int open( //返回值:大于等于0代表操作成功,返回打开的文件描述符号,=-1,创建或者打开失败,失败可查阅errorno来获取具体错误信息
const char *pathname, //要打开的文明名
int flags, //打开的方式,打开方式包括:O_RDONLY 只读方式 O_WRONLY 只写,O_RDWR读写,O_CREAT创建,O_EXCL文件如果存在,使用此标记,会返回错误
mode_t mode); //指定创建文件的权限,只对创建文件有效,对于打开无效;
2,获取文件大小
int fstat(int fd,//文件描述符号
struct stat*buf);//返回文件属性结构体
返回值:成功返回0;失败返回-1
3,把文件映射成虚拟内存
void *mmap(void *addr, //从进程的那个地址开始映射,如果为NULL,由系统指定;
size_t length, //映射的地址空间的大小
int prot, //内存的保护模式
int flags,//映射模式 有匿名,私有,保护等标记 具体查询man手册;
int fd, //如果为文件映射,则此处为文件的描述符号
off_t offset);//如果为文件映射,则此处代表定位到文件的那个位置,然后开始向后映射。
返回值:映射成功,返回首地址;
4,通过对内存的读写来实现对文件的读写
通常使用:memset 和memcpy来实现操作;
5,卸载映射
int munmap(void *addr, //要卸载的内存的地址
size_t length);//内存的大小
6,关闭文件
int close(int fd); //要关闭的文件描述符号 ,成功返回0,错误返回-1,错误参照errorno;
下边是读取文件的操作:
-
-
-
-
-
-
-
typedef struct{
-
char name[ 20];
-
short age;
-
float score;
-
char sex;
-
}student;
-
int main()
-
{
-
student *p,*pend;
-
//打开文件描述符号
-
int fd;
-
/*打开文件*/
-
fd=open( "user.dat",O_RDWR);
-
if(fd== -1){ //文件不存在
-
fd=open( "user.dat",O_RDWR|O_CREAT, 0666);
-
if(fd== -1){
-
printf( "打开或创建文件失败:%m\n");
-
exit( -1);
-
}
-
}
-
//打开文件ok,可以进行下一步操作
-
printf( "open ok!\n");
-
//获取文件的大小,映射一块和文件大小一样的内存空间,如果文件比较大,可以分多次,一边处理一边映射;
-
struct stat st; //定义文件信息结构体
-
/*取得文件大小*/
-
int r=fstat(fd,&st);
-
if(r== -1){
-
printf( "获取文件大小失败:%m\n");
-
close(fd);
-
exit( -1);
-
}
-
int len=st.st_size;
-
/*把文件映射成虚拟内存地址*/
-
p=mmap( NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED,fd, 0);
-
if(p== NULL || p==( void*) -1){
-
printf( "映射失败:%m\n");
-
close(fd);
-
exit( -1);
-
}
-
/*定位到文件开始*/
-
pend=p;
-
/*通过内存读取记录*/
-
int i= 0;
-
while(i<(len/ sizeof(student)))
-
{
-
printf( "第%d个条\n",i);
-
printf( "name=%s\n",p[i].name);
-
printf( "age=%d\n",p[i].age);
-
printf( "score=%f\n",p[i].score);
-
printf( "sex=%c\n",p[i].sex);
-
i++;
-
}
-
/*卸载映射*/
-
munmap(p,len);
-
/*关闭文件*/
-
close(fd);
-
}