关于系统级I/O的相关学习日志

考试之前光顾着复习书本上的知识点和fork那些代码,忽视了这个第十章给的代码,考完试了又因为拖延症和上课上晕了,现在才开始动笔。真的要告诫自己不能再拖拖拖了。

基础知识点

这一章的基础知识主要包括Linux系统的目录层次结构 、Unix I/O函数的使用、共享文件和I/O重定向等等。

  1. Linux系统的目录层次结构 如下图所示:
    在这里插入图片描述
    其中较常碰到的有:
    / ——第一层次结构的根、整个文件系统层次结构的根目录。
    bin/ ——面向所有用户的必要命令(可执行文件)。
    dev/ ——所有必要设备。
    home/ ——用户的家目录即主目录。
    usr/include/ ——用来存放Linux下开发和编译应用程序所需要的头文件。
    等等…

  2. Unix I/O函数
    (1)打开文件:进程通过open函数打开一个已经存在的文件或者创建一个新文件。

int open(char *filename,int flags,mode_t mode);
//返回:成功 返回文件描述符  出错 返回-1

(2)关闭文件:进程通过close函数关闭一个打开的文件。

int close(int fd);
//成功返回0 出错-1 关闭一个已经关闭的描述符会出错

(3)读文件:

ssize_t read(int fd,void *buf,size_t n);
//成功 返回读的字节数 结束为0,出错为-1

(4)写文件:

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

(5)读取文件元数据:

int stst(const char *filename,struct stst *buf);
//成功返回0 出错则为-1
  1. 共享文件和I/O重定向
    (1)共享文件
    ——描述符表。每个进程拥有独立的描述符表,表项由该进程打开的文件描述符来索引,每个打开的表项指向一个文件表中的一个表项。
    ——文件表。所有进程共享,所有打开文件的集合,表项中包括当前的文件位置,引用计数以及一个指向v-node表的指针。
    ——v-node表。所有进程共享这张v-node表,每个表项里包含stat结构中的大多数信息。
    (2)IO重定向:
int dup2(int oldfd,int newfd);
//成功返回描述符,出错为-1

三个习题代码

一、代码1

abcde.txt
abcde
#include "csapp.h"

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;
}

代码运行结果为:
在这里插入图片描述
首先,fd1、fd2、fd3各通过open函数得到描述符,各自指向一个文件表表项,此时读到的字符都是第一个字符a。
而接着调用的dup2(fd2, fd3)使得fd3的描述表项内容被fd2覆盖,所以此时fd3和fd2指向同一个文件表表项。
最后调用read函数时,fd1、fd2读到的结果都为a,fd3读文件从fd2读过后的位置开始,因此结果得到b。

二、代码2

#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函数前,调用read得到c1的值为a。
接着调用fork函数生成父子进程。父进程打开文件fd1,读取c2,还需要休眠等待fork子进程结束;子进程继承了父进程打开的文件fd1,所以子进程的描述符表和父进程指向同一个文件表,读到的c2为b之后的c。

三、代码3

#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;
}

代码运行结果为:
在这里插入图片描述
在这里插入图片描述
fd1打开abcde.txt后因标识符O_CREAT|O_TRUNC|O_RDWR清空原有内容,写入pqrs4个字符。
接下来再次打开文件fd3,因为 O_APPEND标志,所以接下来的jklmn在s后接着写入。
fd2和fd1指向同一个文件表项,wxyz接着上一次对fd1写入后的位置开始写,jklmn被wxyz覆盖后还剩一个n。接着写入fd3加入ef。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值