csapp第十章学习笔记

打开和关闭文件

一个进程在存在期间,会有一些文件被打开,从而会返回一些文件描述符(文件描述符实际上是指向文件表项的指针数组索引,也就相当于每个文件描述符都对应一个文件表项,最终对应一个文件),从shell中运行一个进程,默认会有3个文件描述符存在(0、1、2), 0与进程的标准输入相关联,1与进程的标准输出相关联,2与进程的标准错误输出相关联,一个进程当前有哪些打开的文件描述符可以通过/proc/进程ID/fd目录查看。

进程通过调用open函数打开一个已存在的文件或者创建一个新文件,原型如下:

int open(char *filename, int flags, mode_t mode);

返回值:在进程中当前没有打开的最小描述符
filename:要打开的文件名,通过这个函数将其转换为一个文件描述符
flags:指明进程打算如何访问这个文件(O_RDONLY:只读;O_WRONLY:只写;O_RDWR:可读可写),也可以是更多位掩码的或,为写提供一些额外的提示:

  • O_CREAT:如果文件不存在,就创建它的一个截断的(truncated)(空)文件
  • O_TRUNC:如果文件已存在,就截断它
  • O_APPEND:在每次写操作前,设置文件位置到文件结尾处

mode:指定了新文件的访问权限位

进程通过调用close函数关闭一个打开的文件,原型如下:

int close(int fd);

例1:
foobar.txt由"foobar"组成;baz.txt由”baz"f组成。

int main()
{
 int fd1,fd2;
 
 fd1=Open("foobar.txt",O_RDONLY,0);
 Close(fd1);
 fd2=Open("baz.txt",O_RDONLY,0);
 printf("fd2=%c\n",fd2);
 exit(0);
}

结果:fd2=3
虽然在fd2之前分配了一个fd1的描述符(fd1=3),但随后又关闭了,所以当前没有打开的描述符仍是3.

读和写文件

ssize_t read(int fd, void *buf, size_t n);
返回:若成功为读的字节数,若EOF0,若出错为-1

ssize_t write(int fd, const void *buf, size_t n);
返回:若成功为写的字节数,若出错为-1

例2:

#include "csapp.h"

int main()
{
	int fd1.fd2;
	char c;
	fd1=Open("foobar.txt",O_RDONLY,0);
	fd2=Open("foobar.txt",O_RDONLY,0);
	Read(fd1,&c,1);
	Read(fd2,&c,1);
	printf("c=%c\n",c);	
	exit(0);
}

结果:c=f
多个文件描述符通过不同的文件表表项来引用同一个文件,每个描述符都有它自己的位置,所以对不同的文件描述符的读操作可以从文件的不同位置获取数据。
在上例中,fd1,fd2是引用同一个文件的描述符,均从文件开始位置读取,所以字符c中存储的仍是f.

例3:

#include "csapp"

int main(){
	int fd;
	char c;
	fd=Open("foobar.txt",O_RDONLY,0);
	if(Fork()=0){
		Read(fd,&c,1);
		exit(0);
	}
	Wait(NULL);
	Read(fd,&c,1);
	printf("c=%c\n",c);
	exit(0);
	}

结果:c=o
父进程打开了一个文件,其描述符表中有描述符fd,fork之后,子进程有一个父进程描述符表的副本,父子进程共享相同的打开文件表集合,因此共享相同的文件位置,所以当子进程读取一个字符f后,文件描述符指向文件的第二个字符的位置,则父进程中读取的就是第二个字符o

移动文件指针

重新定位文件读写的位移:
off_t lseek(int fd, off_t offset, int whence);

fd:文件描述符,要定位的文件
offset:偏移量,结合第三个参数使用。为正则向文件末尾移动(向前移),为负数则向文件头部(向后移)
whence:基于文件开头定位,确定新光标位置

  • SEEK_SET: 从文件头部开始偏移offset个字节。

  • SEEK_CUR:从文件当前读写的指针位置开始,增加offset个字节的偏移量。

  • SEEK_END: 文件偏移量设置为文件的大小加上偏移量字节。

I/O重定向

  1. dup函数
int dup(int oldfd);

返回一个新的描述符(复制参数oldfd所指的文件描述符),这个描述一定是当前可用文件描述符中的最小值。
返回的新文件描述符和参数oldfd指向同一个文件,这两个描述符共享同一个数据结构,共享所有的锁定,读写指针和各项全现或标志位。
2. dup2函数

int dup2(int oldfd, int newfd);

返回值:
若dup2调用成功则返回新的文件描述符,出错则返回-1.

区别:dup2与dup区别是dup2可以用参数newfd指定新文件描述符的数值。若参数newfd已经被程序使用,则系统就会将newfd所指的文件关闭,若newfd等于oldfd,则返回newfd,而不关闭newfd所指的文件。dup2所复制的文件描述符与原来的文件描述符共享各种文件状态。共享所有的锁定,读写位置和各项权限或flags等.

例4:

int main()
{
 int fd1,fd2;
 char c;
 
 fd1=Open("foobar.txt",O_RDONLY,0);
 fd2=Open("foobar.txt",O_RDONLY,0);
 Read(fd2,&c,1);
 Dup2(fd2,fd1);
 Read(fd1,&c,1);
 printf("c=%c\n",c);
 exit(0);
}

结果:c=o
通过fd2读取了一个字符之后,指针位置移到了第二个字符的位置,此时将fd2拷贝给fd1,则它们共享文件目前的状态,当读取fd1时,实际上读取的是fd2,则读到的字符为o

当将代码改为如下所示时:

int main()
{
 int fd1,fd2,fd;
 char c;
 
 fd1=Open("foobar.txt",O_RDONLY,0);
 fd2=Open("foobar.txt",O_RDONLY,0);
 Read(fd2,&c,1);
 fd=Dup(fd2);
 Read(fd,&c,1);
 printf("c=%c\n",c);
 exit(0);
}

结果:c=o
可见dup和dup2有相同的效果,区别仅在于,dup产生一个新的描述符,而dup2可对已存在的两个文件描述符进行操作。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值