从实例中学习系统I/O(入门级)

I/O即输入/输出,此日志只讨论Unix I/O

基础知识

  1. 一切皆文件。所有的I/O设备都被模型化为文件,则所有输入/输出都被当作对相应文件的读和写来执行。
  2. 描述符。打开文件时内核会返回一个小的非负整数,叫做描述符,它在后续对此文件的所有操作中标识这个文件。
  3. Linux shell 创建的每个进程开始时都有三个打开的文件: 标准输入(描述符为0)标准输出(描述符为1)标准错误(描述符为2)
  4. 当前文件位置。对于每个打开的文件,内核保持着一个文件位置k,初始为0。这个文件位置是从文件开头起始的字节偏移量
  5. 读写文件。一个读操作就是从文件复制若干字节到内存,类似的,写操作就是从内存复制若干字节到文件,从当前文件位置k开始写,并且更新k。
  6. 文件操作函数

打开或创建文件

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

open函数将filename转换成一个文件描述符,并且返回描述符数字。

flags参数指明指明了进程打算如何访问这个文件:

  • O_RDONLY:只读
  • O_WRONLY:只写
  • O_RDWR:可读可写
  • O_CREAT:如果文件不存在,就创建一个空文件
  • O_TRUNC:如果文件存在,则清空它
  • O_APPEND:每次写操作前,设置文件位置到文件结尾处

mode指定新文件的访问权限位,具体不再详说。

关闭文件

int close(int fd);

fd为文件描述符

读写文件

ssize_t read(int fd,void *buf,size_t n);
ssize_t write(int fd,const void *buf,size_t n);

read函数从描述符为fd的当前文件位置复制最多n个字节到内存位置buf。返回值-1表示一个错误,而返回值0表示EOF。否则,返回值表示实际传送的字节数量。

write函数从内存位置buf复制最多n个字节到描述符为fd的当前文件位置。

实例分析

在运行下列代码前需要导入csapp.c和csapp.h文件,需与下列代码文件存在同一目录下。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}
编译运行

在编译之前需要进行链接

在这里插入图片描述
运行结果

在这里插入图片描述

知识点介绍

dup2函数

int dup2(int oldfd,int newfd);
  • dup2函数复制描述符表表项oldfd到描述符表项newfd,覆盖描述符表项newfd以前的内容。

  • 可以通过下面这个例子加强理解
    在调用dup2之前的状态:
    在这里插入图片描述
    调用dup2(4,1)之后:在这里插入图片描述

代码分析
  • 第一次打开abcde.txt后,文件描述符为fd1,当前文件位置为0,read函数读取第一个字节,故c1=a。

  • 第二次打开abcde.txt后,文件描述符为fd2,当前文件位置依旧为0(相当于打开了一个新文件),read函数读取第一个字节,并更新当前文件位置为1,故c2=a。

  • 第三次打开abcde.txt后,文件描述符为fd3,但dup2函数使fd3指向了fd2指向的文件,所以read函数从当前文件位置为1开始读取第二个字节,故c3=b。

实例二
#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父进程运行时getpid函数返回子进程的pid,子进程运行时返回0。
  • sleep函数可以让进程休眠指定的秒数。
代码分析
  • 第一个read函数读取文件中第一个字节,并更新当前文件位置,故c1=a。
  • 调用fork函数后父进程和子进程并发进行。子进程复制了父进程的环境。
  • 程序先进入父进程(也有先进入子进程的可能性),read函数读取第二个字节,并更新当前文件位置,故此时c2=b。后进入子进程中,子进程复制了父进程的文件表表项,read函数从当前文件位置开始读取第三个字节,故此时c2=c。
实例三
#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);
    Write(fd2, "wxyz", 4);
    Write(fd3, "ef", 2);
    Close(fd1);
    Close(fd2);    
    Close(fd3);
    return 0;
}
编译运行

命令行

在这里插入图片描述
运行结果

在这里插入图片描述

知识点介绍
  • 创建一个文件,若原文件存在,则清空它,代码如下:
fd1 = Open(fname, O_CREAT|O_TRUNC|O_RDWR, S_IRUSR|S_IWUSR);
  • 向文件中添加字节,打开文件后当前文件位置为文件中所有字节末尾,代码如下:
 fd3 = Open(fname, O_APPEND|O_WRONLY, 0);
  • 此代码效果等同于dup2(1,2)
 fd2 = dup(fd1); 
代码分析
  • 第一次打开文件后,文件描述符为fd1,write函数将“pqrs”字符串写进了文件,并更新了当前文件位置。
  • 第二次打开文件后,文件描述符为fd3,当前文件位置为所有字节末尾,故write函数在“pqrs”字符后添加了“jklmn”。
  • 调用dup函数后,fd2指向了fd1所指文件,故write函数从“s”字符后开始写,“wxyz”覆盖了“jklm”。
  • fd3所指文件的当前文件位置为末尾,故最后一个write字符从末尾开始写,将“ef”添加进文件中。
  • 故最后文件中的字符串为“pqrswxyznef”。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值