深入理解计算机系统第10章

学习意义

输入/输出(I/O)是在主存和外部设备之间复制数据的过程。输入操作是从I/O设备复制数据到主存,而输出操作相反。
所有语言的运行时系统都提供执行I/O的较高级别的工具。

  • 了解Unix I/O将帮助你理解其他的系统概念

Unix I/O

将设备映射为文件,允许linux内核引出一个简单低级的应用接口。

文件

绝对路径名:从根节点开始的路径。
相对路径名:以文件名开始,从当前工作目录开始的路径。

打开和关闭文件

open函数返回新文件描述符。在这里插入图片描述
flags参数可为一位或更多位掩码的或,为写提供额外指示。
close函数:关闭一个打开的文件。
在这里插入图片描述

读和写文件

在这里插入图片描述
read函数从描述符fd的当前文件位置复制最多n个字节到内存位置buf。
write函数从内存位置buf复制最多n个字节到描述符fd的当前文件位置。

读取文件元数据

应用程序调取stat和fstat函数检索关于文件的信息(即文件的元数据)
在这里插入图片描述
在这里插入图片描述

共享文件

Linux内核用三个数据结构来表示打开的文件。

  • 描述符表(descriptionor table)
    每个进程都拥有一个独立的描述符表, 表项是由该进程打开的描述符来索引的,每个打开的描述符表项指向文件表中的一个表项。
  • 文件表(file table)
    打开文件的集合由该表来维护,所有进程共享该表,文件表有个表项,它是由三个部分组成,分别是:该文件的位置,描述符表的应用计数,和v-node表的表项指针。
  • v-node表
    所有进程共享该表。每个表项包含stat结构中的大多数信息,包括st_mode和st_size成员。
    在这里插入图片描述
    多个描述符通过不同的文件表表项引用同一个文件。
    在这里插入图片描述
    父子进程共享文件,调用fork后,子进程有一个父进程描述符表的副本。
    在这里插入图片描述
    示例:
    在这里插入图片描述

I/O重定向

①dup2函数
在这里插入图片描述
dup2函数复制描述符表表项oldfd到描述符表表项newfd,覆盖描述符表表项newfd以前的内容。如果newfd已经打开了,dup2会在复制oldfd之前关闭newfd。
示例:
在这里插入图片描述
②相关程序示例:

#include "csapp.h"
 
int main(int argc, char *argv[])
{
    int fd1;
    int s = getpid() & 0x1;
    char c1, c2;
    char *fname = argv[1];
    fd1 = Open(fname, O_RDONLY, 0);
    Read(fd1, &c1, 1);
    if (fork()) {
	/* Parent */
	sleep(s);
	Read(fd1, &c2, 1);
	printf("Parent: c1 = %c, c2 = %c\n", c1, c2);
    } else {
	/* Child */
	sleep(1-s);
	Read(fd1, &c2, 1);
	printf("Child: c1 = %c, c2 = %c\n", c1, c2);
    }
    return 0;
}

输入:在这里插入图片描述

运行结果:在这里插入图片描述
在fork之前,进程打开文件abcde.txt返回fd1,然后用fd1读取到了文件abcde.txt的第一个字符a并赋值给c1。
fork之后父进程调用sleep等待子进程结束。子进程继承了父进程打开的文件,所以子进程描述符表中的fd1和父进程的fd1表项内容相同。因此子进程再使用fd1读取文件abcde.txt时读到是第2个字符。
父进程在子进程结束后使用fd1读取文件abcde.txt读取第三个字符。

#include "csapp.h"
 
int main(int argc, char *argv[])
{
    int fd1, fd2, fd3;
    char *fname = argv[1];
    fd1 = Open(fname, O_CREAT|O_TRUNC|O_RDWR, S_IRUSR|S_IWUSR);
    Write(fd1, "pqrs", 4);	
 
    fd3 = Open(fname, O_APPEND|O_WRONLY, 0);
    Write(fd3, "jklmn", 5);
    fd2 = dup(fd1);  /* Allocates new descriptor */
    Write(fd2, "wxyz", 4);
    Write(fd3, "ef", 2);
 
    Close(fd1);
    Close(fd2);
    Close(fd3);
    return 0;
}

输入结果:在这里插入图片描述
运行结果:pqrswxyznef
fd1写入“pqrs”,fd3在打开文件时用到了O_APPEND,所以fd3写入时不会覆盖原有的内容,而是在已有内容后附加新的内容,这样就写入了“jklmn"。文件内容变成了“pqrsjklmn”。
然后对于fd2,fd2 = dup(fd1),所以fd2使用fd1的光标,写入“wxyz”,文件内容变为“pqeswxyzn”。
再使用fd3附加在原有内容之后写入了”ef",文件内容变成了“pqrswxyznef"。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值