回顾:
string的操作 - 代码要熟练(超重点)
内存分配的几个函数 - malloc() free() sbrk() brk()
zhanglm@tarena.com.cn
今天:
mmap()和munmap() - 针对物理内存的映射(不包括映射文件)
Unix/Linux系统函数 - 关于文件读写的(重点)
经验:在应用开发中,多个权限或者多个选项 之间用 位或 | 连接。
r - 100
w - 010
x - 001
rw rx -> rwx
110 101 -> 111
110
101 (位或|)
--------
111
void* mmap(void* addr,size_t size,int prot,int flags,
int fd,off_t offset)
功能:创建一个新的 内存映射(可能映射 文件或内存)
参数:addr 允许程序员指定映射的首地址,一般为NULL交给内核指定。size 就是分配内存的大小,最好是 4096的整数倍,如果不是,也会映射 内存页的整数倍。prot是 内存的访问权限,一般写:PROT_READ|PROT_WRITE 即可。flags是映射的选项,必须包含以下两个之一:
MAP_PRIVATE - 只有本进程使用
MAP_SHARED - 运行其他进程使用,但只对 映射文件有效。
默认情况下,mmap()映射的是文件,想映射物理内存,必须在flags指定 MAP_ANONYMOUS .
fd和offset 只对 映射文件有效,映射物理内存时给 0 即可。
返回 映射成功返回首地址,失败 返回 (void*)-1 (MAP_FAILED)
系统调用 - 用户层的程序不能直接使用内核空间,而从功能上需要内核空间完成,因此,Unix系统提供了大量的系统函数,用户程序通过调用这些系统函数进入内核空间,完成功能。这些函数 统称为 系统调用。(system call)
Linux系统中,几乎一切都可以看成文件。目录是文件,内存是文件,各种设备也都是文件。因此,操作文件的函数 可以 操作各种设备。
关于文件的系统函数:
通用的
open() - 打开一个文件,返回 文件描述符
read() - 读文件
write() - 写文件
close() - 关闭 打开的文件
文件描述符 其实就是一个整数,对应一个 打开的文件。
读写文件时,有几个步骤:
1 首先要在硬盘上找到文件,查找文件 其实 是依靠 i节点(inode),i节点就是 文件在硬盘上的地址,也是整数。ls -i就可以看到i节点。
2 CPU 不能直接操作 硬盘上的文件,因此硬盘上的文件 必须放入内存中才能使用。
3 文件描述符 就是文件读入内存后的代表,是 内存中代表一个打开的文件的整数。
4 程序通过 操作文件描述符 实现对文件的读写操作。
文件描述符 其实 没有存储任何文件的信息,就是一个非负的整数编号,文件描述符 其实 在内存中对应了一张文件表,文件的信息存在文件表中。
每个进程都有一个文件描述符 总表,总表中 记录了已经使用的文件描述符和文件表的对应关系。文件描述符的0 1 2 被系统占用,代表标准输入、标准输出和标准错误,因此文件描述符其实从3开始。
open()函数 其实 是先打开一个文件,把文件的信息存入文件表,然后去文件描述符总表中 查找未使用的最小值,然后把对应关系写入总表,并把文件描述符的值返回。
close()函数 其实 就是从 文件描述符总表中 删除 对应关系,但不一定删除文件表。只有 没有关系的 文件表 才会被删除。
int open(char* filename,int flags,...)
功能:打开一个文件,返回文件的描述符
参数:filename 就是文件名(带路径的),flags是打开的方式,包括
O_RDONLY / O_WRONLY / O_RDWR - 3选1,代表打开权限
O_CREAT - 如果文件不存在会创建新文件,不写 就不会新建文件
O_EXCL - 和O_CREAT一起用,代表文件如果不存在新建,存在不打开而是直接 返回错误 -1
O_TRUNC - 清空已存在文件的内容(小心使用,可能误删数据)
O_APPEND - 以追加的方式打开文件,文件的读写位置不是文件头,而是文件的末尾。
... 代表0-N个参数,在新建文件时需要第三个参数,是新文件在硬盘上的权限,采用 8进制。
返回: 成功返回文件描述符,失败返回 -1 。
read() 和 write()
都是三个参数一个返回值,用于读写文件
参数:第一个参数是 文件描述符,open()的返回值。
第二个参数就是 读/写的 首地址。
第三个参数 read() 是 buf的大小,而 write() 是 数据的大小
返回:
成功都返回实际读/写的字节数,失败都返回 -1 。
read() 用返回0 代表读到了文件尾。
练习:
员工管理系统的模块 - 增加员工模块、查询员工信息模块
员工的信息包括:员工编号id、员工姓名name、员工薪水sal
做成一个结构体。
增加员工的流程:用户输入(scanf())员工的id、name和sal,然后放入结构体中,把结构体写入文件中。
查询员工信息的流程:就是把所有员工信息从文件中读出来,读到结构体中并打印出来。
提示&要求: 把结构体写入 头文件 .h 中。