文件系统 - d05

回顾:
  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 中。