1 / 110

第 5 章

第 5 章. 文件I/O操作. 本章重点. Linux 系统的文件属性 不带缓存的文件 I/O 操作 基于流的文件 I/O 操作 特殊文件的操作. 2. 5.1 Linux 系统文件和文件系统. 文件是指有名字的一组相关信息的集合。文件系统是操作系统用来管理和保存文件的。 Linux 的文件系统目录结构是属于 树形结构 。因此,文件系统的开始是由根目录( / )开始往下长,就像一棵倒长的树一样。 Linux 把不同文件系统挂载 (mount) 在根文件系统下不同的子目录(挂载点)上,用户可以从根( / )开始方便找到存放在不同文件系统的文件。

donar
Télécharger la présentation

第 5 章

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第 5 章 文件I/O操作

  2. 本章重点 • Linux系统的文件属性 • 不带缓存的文件I/O操作 • 基于流的文件I/O操作 • 特殊文件的操作 2

  3. 5.1 Linux系统文件和文件系统 • 文件是指有名字的一组相关信息的集合。文件系统是操作系统用来管理和保存文件的。 • Linux 的文件系统目录结构是属于树形结构。因此,文件系统的开始是由根目录(/)开始往下长,就像一棵倒长的树一样。 • Linux把不同文件系统挂载(mount)在根文件系统下不同的子目录(挂载点)上,用户可以从根(/)开始方便找到存放在不同文件系统的文件。 • 在安装Linux系统时,系统会建立一些默认的目录,而每个目录都有其特殊功能。

  4. 5.1 Linux系统文件和文件系统 linux文件系统结构

  5. 5.1.1 Linux文件类型 • Linux文件类型分为普通文件、目录文件、符号链接(symbolic link)文件、设备文件、管道文件、socket文件等。 • 例5.1 设计一个程序,要求列出当前目录下的文件信息,以及系统“/dev/sda1”和“/dev/lp0”的文件信息。 • 步骤1 编辑源程序代码。 [root@localhost root]#vi 5-1.c

  6. 5.1.1 Linux文件类型

  7. 5.1.1 Linux文件类型 • 步骤2 用gcc编译程序。 [root@localhost root]#gcc 5-1.c –o 5-1 • 步骤3 运行程序。 [root@localhost root]#./5-1 列出当前目录下的文件信息: -rwxr-xr-x 2 root root 12255 7月 11 04:22 file01 -rw-r--r-- 1 root root 786 7月 11 04:21 file02 drwxr-xr-x 7 root root 4096 5月 11 04:21 file03 lrwxrwxrwx 1 root root 11 7月 11 04:20 file04-> etc/passwd -rwxr-xr-x 2 root root 12255 7月 11 04:22 file05 列出“/dev/sda1”的文件信息: brw-rw---- 1 root disk 8, 1 2003-01-30 /dev/sda1 列出“/dev/ lp0”的文件信息: crw-rw---- 1 root lp 6, 0 2003-01-30 /dev/lp0

  8. 5.1.1 Linux文件类型 • 用ls命令长列表显示文件类型含义如表5.1所示

  9. 5.1.1 Linux文件类型 • system函数说明 :

  10. 5.1.2 文件权限 • Linux系统是一个多用户系统。为了保护系统中文件的安全,Linux统对不同用户访问同一文件的权限做了不同的规定。 • 对于Linux系统中的文件来说,它的权限可以分为四种:可读取(Read)、可写入(Write)、可执行(eXecute)和无权限,分别用r、w、x和-表示。 • 例5.2 设计一个程序,要求把系统中“/etc”目录下的passwd文件权限,设置成文件所有者可读可写,所有其他用户为只读权限。 10

  11. 5.1.2 文件权限 • 步骤1 编辑源程序代码。 [root@localhost root]#vi 5-2.c 程序代码如下: /*5-2.c 设置“/etc/passwd”文件权限*/ #include<sys/types.h> /*文件预处理,包含chmod函数库*/ #include<sys/stat.h> /*文件预处理,包含chmod函数库*/ int main () /*C程序的主函数,开始入口*/ { chmod("/etc/passwd",S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); /*S_IRUSR表示拥有者具有读权限,S_IRGRP表示组内人具有读权限,S_IROTH表示其他人具有读权限*/ return 0; }

  12. 5.1.2 文件权限 • 步骤2 用gcc编译程序。 [root@localhost root]#gcc 5-2.c –o 5-2 • 步骤3 运行程序。 [root@localhost root]#./5-2 如果程序没有出错,此时系统中没有任何显示。 • 步骤4 使用ls –l命令来查看“/etc/passwd”文件的权限。 [root@localhost root]#ls -l /etc/passwd -rw-r--r-- 1 root root 1635 3月 15 00:20 /etc/passwd

  13. 5.1.2 文件权限 • 例5.3 设计一个程序,要求设置系统文件与目录的权限掩码。 • 分析 先将系统的权限掩码改为0666(指建立文件时预设的权限为0000),然后调用touch命令新建文件liu1;接着将系统的权限掩码设为0444(指建立文件时预设的权限为0222),然后调用touch命令新建文件liu2;最后调用ls命令观察这些文件的权限,是否按题意的要求已实现。 • 步骤1 编辑源程序代码。 [root@localhost root]#vi 5-3.c

  14. 5.1.2 文件权限 • 步骤2 用gcc编译程序。 [root@localhost root]#gcc 5-3.c –o 5-3 • 步骤3 运行程序。 [root@localhost root]#./5-3 系统原来的权限掩码是:123 系统新的权限掩码是:666 创建了文件liu1 系统原来的权限掩码是:666 系统新的权限掩码是:444 创建了文件liu2 ---------- 1 root root 0 7月 17 20:59 liu1 --w--w--w- 1 root root 0 7月 17 20:59 liu2

  15. 5.1.2 文件权限 • 上述结果说明如下: • 1)先将系统的权限掩码为0666,所以新建的文件liu1访问权限为0000,即“--------”。 • 2)再将系统的权限掩码为0444,所以新建的文件liu2访问权限为0222,即“--w--w--w-”。 • 语句system("touch liu1")的作用是调用system函数来运行shell命令“touch liu1”,touch命令的作用是更改时间标记,若文件不存在,则新建文件。 • 运行一次此例的程序后,修改源程序中的掩码后,再次编译运行,文件“liu1”和“liu2”的权限并不改变。因为如果文件已经存在,touch只修改时间标记。如果要再次验证新的掩码,需要再次运行程序前删除原来的文件。

  16. 5.1.2 文件权限 • chmod函数说明 :

  17. 5.1.2 文件权限 • mode参数说明 :

  18. 5.1.2 文件权限 • umask函数说明 : 思考题:设计一个程序,要求Linux系统新建的文件权限是0400,提示umask中的参数设置为0266。

  19. 5.1.3 Linux文件的其他属性 • 在Linux系统中,文件还有创建时间、大小等其他的属性。这些信息定义在stat结构体中。 • stat结构的定义如下: struct stat { dev_t st_dev; /*文件所在设备的ID*/ ino_t st_ino; /*索引节点号*/ mode_t st_mode; /*文件保护模式*/ nlink_t st_nlink; /*文件的连接数(硬连接)*/ uid_t st_uid; /*用户ID*/ gid_t st_gid; /*组ID*/ dev_t st_rdev; /*设备号,针对设备文件*/ off_t st_size; /*文件字节数*/ unsigned long st_blksize; /*系统块的大小*/ unsigned long st_blocks; /*文件所占块数 */ time_t st_atime; /*最后一次访问时间*/ time_t st_mtime; /*最后一次修改时间*/ time_t st_ctime; /*最后一次改变时间(指属性)*/ };

  20. 5.1.3 Linux文件的其他属性 • 要获得文件的其他属性,可以使用stat函数、fstat或lstat函数。 • fstat函数返回与打开的文件描述符相关的文件的状态信息,该信息将会写到stat结构中,stat的地址以参数形式传递给fstat。 • stat和lstat返回的是通过文件名查到的状态信息。它们的结果基本一致,但当文件是一个符号链接时,lstat返回的是该符号链接本身的信息,而stat返回的是该链接指向的文件的信息。

  21. 5.1.3 Linux文件的其他属性 • 例5.4 设计一个程序,应用系统函数stat获取系统中“/etc”目录下的passwd文件的大小。 • 步骤1 编辑源程序代码。 [root@localhost root]#vi 5-4.c 程序代码如下: /*5-4.c 获取“/etc/passwd”文件的大小*/ #include<unistd.h> /*文件预处理,包含stat函数库*/ #include<sys/stat.h> /*文件预处理,包含stat函数库*/ int main () /*C程序的主函数,开始入口*/ { struct stat buf; stat("/etc/passwd",&buf); printf("“/etc/passwd”文件的大小是:%d\n",buf.st_size); return 0; }

  22. 5.1.3 Linux文件的其他属性 • 步骤2 用gcc编译程序。 [root@localhost root]#gcc 5-4.c –o 5-4 • 步骤3 运行程序。 [root@localhost root]#./5-4 “/etc/passwd”文件的大小是:1635 由结果可知,运行此程序后,在没有打开文件“/etc/passwd”的情况下,通过stat函数取得了文件大小。

  23. 5.1.3 Linux文件的其他属性 • stat函数说明 :

  24. 5.1.3 Linux文件的其他属性 • 思考题: • 设计一个程序,要求判断“/etc/passwd”的文件类型。 使用st_mode属性,可以使用几个宏来判断:S_ISLNK(st_mode) 是否是一个连接,S_ISREG是否是一个常规文件S_ISDIR是否是一个目录,S_ISCHR是否是一个字符设备,S_ISBLK是否是一个块设备,S_ISFIFO是否是一个FIFO文件,S_ISSOCK是否是一个SOCKET文件。 • 设计一个程序,要求打开文件“/etc/passwd”,判断它的最后一次访问时间。 • 应用命令:man fstat,查阅文件状态相关的应用: int stat(const char *file_name, struct stat *buf); int fstat(int filedes, struct stat *buf); int lstat(const char *file_name, struct stat *buf); • 请查阅相关资料,如何利用结构体struct stat成员获取文件类型。

  25. 5.2 不带缓存的文件I/O操作 • Linux系统把目录、设备等的操作,都等同于文件的操作。Linux系统通过一个文件描述符来进行区分引用。文件描述符是一个非负的整数,是一个索引值,指向内核中每个进程打开文件表。 • Linux系统中,基于文件描述符的文件操作主要有:不带缓存的文件I/O操作和带缓存的文件流I/O操作。 • 不带缓存的文件I/O操作是系统调用或API的I/O操作,由操作系统提供的,符合POSIX标准,设计的程序能在各种支持POSIX标准的操作系统中方便地移植。 • 不带缓存的文件I/O程序不能移植到非POSIX标准的系统(如Windows系统)上去,但是在嵌入式程序设计、TCP/IP的Socket套接字程序设计、多路I/O操作程序设计等方面应用广泛。

  26. 5.2 不带缓存的文件I/O操作

  27. 5.2.1 文件的创建 • 在Linux C程序设计中,创建文件可以调用creat函数。 • 例5.5 设计一个程序,要求在“/root”目录下创建一个名称为“5-5file”的文件,并且把此文件的权限设置为所有者具有只读权限,最后显示此文件的信息。 • 步骤1 编辑源程序代码。 [root@localhost root]#vi 5-5.c

  28. 5.2.1 文件的创建 • 程序代码如下: /*5-5.c程序:在“/root”目录下创建一个名称为“5-5file”的文件*/ #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> int main() { int fd; fd=creat("/root/5-5file",S_IRUSR); /*所有者具有只读权限 */ system("ls /root/5-5file -l");/*调用system函数执行命令ls显示此文件的信息 */ return 0; }

  29. 5.2.1 文件的创建 • 步骤2 用gcc编译程序。 [root@localhost root]#gcc 5-5.c –o 5-5 • 步骤3 运行程序。 [root@localhost root]#./5-5 -r-------- 1 root root 0 7月 17 22:00 /root/5-5file

  30. 5.2.1 文件的创建 • creat函数说明 : 思考题:设计一个程序,要求在“/mnt”目录下创建一个名称为“usb”的文件,编辑、调试成功后,运行两次是否有问题?为什么?

  31. 5.2.2 文件的打开和关闭 • 文件的打开可以用open函数,即使原来的文件不存在,也可以用open函数创建文件。在打开或者创建文件时,可以指定文件的属性及用户的权限等参数。 • 关闭一个打开的文件,用close函数。当一个进程终止时,它所有已打开的文件都由内核自动关闭。 • 例5.6 设计一个程序,要求在“/root”下以可读写方式打开一个名为“5-6file”的文件。如果该文件不存在,则创建此文件;如果存在,将文件清空后关闭。 • 步骤1 编辑源程序代码。 [root@localhost root]#vi 5-6.c

  32. 5.2.2 文件的打开和关闭

  33. 5.2.2 文件的打开和关闭 • 步骤2 用gcc编译程序。 [root@localhost root]#gcc 5-6.c –o 5-6 • 步骤3 运行程序。 [root@localhost root]# ./5-6 打开(创建)文件“5-6file”,文件描述符为:3 -rw------- 1 root root 0 7月 17 22:07 /root/5-6file

  34. 5.2.2 文件的打开和关闭 • open函数说明:

  35. 5.2.2 文件的打开和关闭 • flags参数说明 :

  36. 5.2.2 文件的打开和关闭 • close函数说明 : 思考题:设计一个程序,要求在“/mnt”目录下打开名称为“usb”的文件。如果该文件不存在,则创建此文件;如果存在,将文件清空后关闭。

  37. 5.2.3 文件的读写操作 • 文件读写操作中,经常用到的函数是read、write和lseek。 • read函数用于将指定的文件描述符中读出数据。 • write函数用于向打开的文件写数据,写操作从文件当前位置开始。 • lseek函数用于在指定的文件描述符中将文件指针定位到相应的位置。

  38. 5.2.3 文件的读写操作 • 例5.7 程序从终端读数据再写回终端。 #include <unistd.h> #include <stdlib.h> int main(void) { char buf[80]; int n; n = read(STDIN_FILENO, buf,80); if (n < 0) { perror("read STDIN_FILENO"); exit(1); } write(STDOUT_FILENO, buf, n); printf("\n"); return 0; }

  39. 5.2.3 文件的读写操作 • 例5.8 设计一个C程序,完成文件的复制工作。要求通过使用read函数和write函数复制“/etc/passwd”文件到目标文件中,目标文件名在程序运行时从键盘输入。 • 分析 由用户输入目标文件的名称,接着打开源文件“/etc/passwd”及目标文件,利用read函数读取源文件的内容,再利用write函数将读取到的内容写入至目标文件。 • 步骤1 编辑源程序代码。 [root@localhost root]#vi 5-8.c

  40. 5.2.3 文件的读写操作

  41. 5.2.3 文件的读写操作

  42. 5.2.3 文件的读写操作 • 步骤2 用gcc编译程序。 [root@localhost root]#gcc 5-8.c –o 5-8 • 步骤3 运行程序。 [root@localhost root]#./5-8 请输入目标文件名:5-8test 复制"/etc/passwd"文件为"5-8test"文件成功!

  43. 5.2.3 文件的读写操作 • read函数说明 :

  44. 5.2.3 文件的读写操作 • write函数说明 :

  45. 5.2.3 文件的读写操作 思考题: 1.设计一个程序,使用read函数从源文件读取数据,再用write函数写入到目标文件,源文件名和目标文件名都由键盘输入。 2.设计一个程序,要求在“/mnt”目录下,打开名称为“usb”的文件,如果该文件不存在,则创建此文件,如果已存在,把字符串“usb作为优盘设备文件”写入此文件后关闭。

  46. 5.2.3 文件的读写操作 • 如果在open一个设备时指定了O_NONBLOCK标志,read/write就不会阻塞。以read为例,如果设备暂时没有数据可读就返回-1,同时置errno为EWOULDBLOCK,表示本来应该阻塞但事实上并没有阻塞而是直接返回错误,通过轮询方式试着再读一次,而不是阻塞在这里死等,这样可以同时监视多个设备。 • 在使用非阻塞I/O时,通常不会在一个while循环中一直不停地查询(这称为Tight Loop),而是每延迟等待一会儿来查询一下,以免做太多无用功,在延迟等待的时候可以调度其它进程执行。

  47. 5.2.3 文件的读写操作 • 例5.9 以下是一个非阻塞I/O的例子,程序打开当前终端文件/dev/tty,在打开时指定O_NONBLOCK标志。程序运行时每隔一定时间(6秒)等待用户从终端输入,等待30秒,每次等待时屏幕都有提示“”,30秒后程序继续执行主程序,输出以下图形后结束。

  48. 5.2.3 文件的读写操作

  49. 5.2.3 文件的读写操作

  50. 5.2.3 文件的读写操作 • 程序运行时,轮询等待用户的输入,等待期间如有输入,即转入主程序执行,如没有输入,30秒后执行主程序,执行结果如下: [root@localhost root]# ./5-9 try again try again try again try again try again timeout * * * * * * * * * * * * * * * [root@localhost root]# ./5-9 try again ls -l try again ls -l * * * * * * * * * * * * * * *

More Related