ffiles的详解

ffiles的详解
1.ffiles1
运行结果如下:

/*
$ gcc ffiles1.c csapp.h csapp.c -lpthread -o ffiles1
$ ./ffiles1 abcde.txt
c1 = a, c2 = a, c3 = b
*/

实际代码如下:

int main(int argc, char *argv[])
{
    int fd1, fd2, fd3;
    char c1, c2, c3;
    char *fname = argv[1];
    fd1 = Open(fname, O_RDONLY, 0);
    fd2 = Open(fname, O_RDONLY, 0);
    fd3 = Open(fname, O_RDONLY, 0);
    dup2(fd2, fd3);

    Read(fd1, &c1, 1);
    Read(fd2, &c2, 1);
    Read(fd3, &c3, 1);
    printf("c1 = %c, c2 = %c, c3 = %c\n", c1, c2, c3);

    Close(fd1);
    Close(fd2);
    Close(fd3);
    return 0;
}

main函数的两个参数,分别为int类型的argc(记录输入的参数个数),字符串数组的argv(存放传进的字符串)。举个例子,在运行这段代码时,我们输入了这个命令 ./ffiles1 abcde.txt,表示argc的值为2,而argv[0]为./ffiles1 argv[1]为abcde.txt。大概就是这个意思,接着继续看一下代码,定义了三个文件描述符(文件描述符是一个非负整数,每一个文件描述符都唯一对应了一个打开的文件,通过文件描述符可以准确打开文件。但是有三个描述符不可使用,分别是fd0:标准输入,fd1:标准输出,fd2:标准出错),以及将argv[1]的值赋给fname,即abcde.txt.然后均以只读的形式读取文件。(
o_rdonly read only 只读
o_wronly write only 只写
o_rdwr read write 可读可写
o_trunc 若文件存在则长度被截为0(属性不变)
o_creat:若文件不存在,则创建它的一个截断的(空)文件
o_append:在每次写操作前,设置文件位置到文件的结尾处,即追加。

 dup2(fd2, fd3);

dup2函数复制描述符表表项oldfd到描述符表表项newfd,覆盖描述符表表项newfd之前的内容,如果newfd已经打开了,dup2会在复制oldfd之前关闭newfd.其标准形式为int dup2(int oldfd,int newfd)
因此在这里fd3将与fd2指向相同的文件。

    Read(fd1, &c1, 1);
    Read(fd2, &c2, 1);
    Read(fd3, &c3, 1);

读取fd1中的一个字符,易得为a,而fd2中的字符也是a,但fd3中读出的字符是b,因为a已经被fd2读出来了。(若未指向同一文件,而是最后共同指向v-node表,那么文件都是互不干涉,相当于重新打开。而指向了同一文件,相当于把这个文件打开两次,记录第一次执行的操作)
简图如下:好丑
在这里插入图片描述
最后就是关闭所有的文件了
2.ffiles2
运行结果如下:(注:Parent与Child输出顺序不唯一)

/*
$ gcc ffiles2.c csapp.h csapp.c -lpthread -o ffiles2
$ ./ffiles2 abcde.txt
Parent: c1 = a, c2 = b
 Child: c1 = a, c2 = c
*/

实际代码如下:

#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;
}
int s = getpid() & 0x1;

if (fork()) {
	/* Parent */
	sleep(s);
	
 } else {
	/* Child */
	sleep(1-s);

获取pid并与0x1做与运算,得出结果为0或1,若为1,则表示父亲要休眠一秒钟,反之孩子要休眠一秒钟。

新创建的子进程几乎但不完全与父进程相同。
子进程可以得到与父进程用户级虚拟地址空间相同的(但是独立的)一份副本
包括代码,数据段,堆,共享库,以及任何打开文件描述符相同的副本

在ffiles2中,父进程与子进程是共享文件描述符的,所以相当于二者指向同一个文件,并且在fork之前要打开文件,不然没有文件描述符加以共享。因此,c1所读取字符为a,而之后只能读取在a之后的字符。
3.ffiles3
运行结果如下:

/*abcde.txt
pqrswxyznef
*/

实际代码如下:

#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;
}
S_IRUSR:使用者(拥有者)能够读取这个文件
S_IWUSR:使用者(拥有者)能够写这个文件
S_IXUSR:使用者(拥有者)能够执行这个文件
S_IRGPR:使用者(拥有者)所在组的成员能够读这个文件
S_IWGPR:使用者(拥有者)所在组的成员能够写这个文件
S_IXGPR:使用者(拥有者)所在组的成员能够执行这个文件
S_IROTH:其他人(任何人)能够读这个文件
S_IWOTH:其他人(任何人)能够写这个文件
S_IXOTH:其他人(任何人)能够执行这个文件
   fd1 = Open(fname, O_CREAT|O_TRUNC|O_RDWR, S_IRUSR|S_IWUSR);
    Write(fd1, "pqrs", 4);	

打开一个文件,如果不存在就创建它,如果存在就截断它,以可读可写的形式打开,返回一个文件描述符,向fd1里面写入pqrs。

    fd3 = Open(fname, O_APPEND|O_WRONLY, 0);
    Write(fd3, "jklmn", 5);

注:fd2(fd1):二者指向同一个文件,但是文件描述符不一样
同样打开fname文件,但是以只写或者追加的方式打开。因此向fd3中写入jklmn.因为fd1与fd3打开的是相同的文件,所以写入fd3,也是在fd1中写入.

    fd2 = dup(fd1);  /* Allocates new descriptor */
    Write(fd2, "wxyz", 4);
    Write(fd3, "ef", 2);

将fd1复制至fd2,此时,fd2与fd1指向相同的文件,向fd2(fd1)中写入wxyz,因为上一次fd1写入的最后为s,所以会从s后面开始写,那么将会把jklm给覆盖掉。最后往fd3中写入ef,fd3上一次写入的最后字符为n,故此时会在n的后面继续往下写。所以最终的结果为pqrswxyznef.
简图如下:过于简单,看懂就行
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值