文件I/O

print函数

printf函数的调用链: printf  write  int 0x80  sys_write

printf和write属于用户层函数,int 0x80相当于一闪门,进入到内核函数sys_write。

sys_write 完成后,再一层一层的将结果返回到 printf。

open函数

//包含头文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
//函数原型
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

1、 flags有3个必选项 O_RDONLY、O_WRONLY、O_RDWR。这三个值是互斥的,只能选一个。

2、flags有很多可选项,O_CREAT、O_APPEND、O_EXCL、O_TRUNC、O_NONBLOCK这些值可以多选。不能和必选项发生冲突。

3、若选择了O_CREAT选项、那么open函数第三个参数mode就必须写。O_EXCL只和O_CREAT配合使用,若开启O_EXCL,而且创建的文件存在,函数返回-1。

4、O_APPEND表示追加的方式打开文件。

5、O_TRUNC表示打开文件将长度截取为0。

6、O_NONBLOCK针对设备文件,比如屏幕网络,表示非阻塞方式打开IO。

flag选项示例:

open('test', O_RDONLY);                     // 只读方式打开
open('test', O_WRONLY | O_APPEND);          // 追加的方式打开
open('test', O_RDWR);                       // 读写的方式打开
open('test', O_WRONLY | O_CREAT, 0666);     // 创建文件,只写,权限是 0666
open('test', O_WRONLY | O_TRUNC);           // 只写打开,同时把文件长度截断成 0.

read函数

//头文件
#include <unistd.h>
//函数原型
ssize_t read(int fd, void *buf, size_t count);
返回值:返回读到的字节数,返回0表示读到文件末尾,返回-1表示出错。

write函数

//头文件
#include <unistd.h>
//函数原型
ssize_t write(int fd, const void *buf, size_t count);

返回值  返回写入的字节数,出错返回-1

lseek函数

//头文件
#include <sys/types.h>
#include <unistd.h>
//函数原型
off_t lseek(int fd, off_t offset, int whence);

改变文件的当前的偏移量。
当open函数打开一个文件的时候,偏移量默认为0
whence的值: SEEK_SET 文件头部   SEEK_CUR 文件尾部 SEEK_END 文件尾部

阻塞IO

通常情况下,从普通文件传数据,会在有限的时间内返回,如果从设备、网络中读取数据如果没有数据可读read一定会堵塞不会返回。

read的这种行为称为block,一旦发生block进程会被操作系统投入随眠,直到等到事件发生进程才被唤醒。

系统调用write同样有可能被阻塞,比如向网络写入数据,若对方不接收,本端缓冲区一旦写满就会被阻塞。

阻塞IO与非阻塞IO效率


阻塞IO与非阻塞IO的几个问题:

1、阻塞与非阻塞是文件本身的特性,不是系统调用read/write可以控制的。

2、终端默认是阻塞的,我们可以重新open设备文件/dev/tty(表示当前终端),打开时指定O_NONBLOCK标志就行了。

3、非阻塞read,如果有数据到来返回读到的字节数。如果没有数据返回-1。

fcntl函数

//头文件
#include <unistd.h>
#include <fcntl.h>
//函数原型
int fcntl(int fd, int cmd, ... /* arg */ );
fcntl函数可以修改文件状态位的标志,fcntl函数第二个参数取不同的值有着不同的功能,如果失败返回-1 。

以上函数使用测试代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>

int main(int argc, char const *argv[])
{
	if (argc != 3)
	{
		printf("输入参数有误。\n");
		return 0 ;
	}

	int srcfd = open(argv[1],O_RDONLY);//只读方式打开文件
	
	perror("open"); 
	if(srcfd == -1)
	{
		return -1 ;
	}

	int dsfd = open(argv[2],O_CREAT | O_WRONLY,0666);
	perror("open");
	if (dsfd == -1)
	{
		return -1 ;
	}

	int len = 0 ;
	char* buff[1024] ;
	memset(buff,0,sizeof(buff));
	while(len = read(srcfd,buff,sizeof(buff)) > 0)
	{
		write(dsfd,buff,sizeof(buff));
		memset(buff,0,sizeof buff);
	}
	lseek(srcfd,-20,SEEK_END);	//将文件指针冲文件末尾向文件头部偏移20字节
	read(srcfd,buff,sizeof buff);
	write(STDOUT_FILENO,buff,sizeof(buff));
	close(dsfd);	//关闭文件
	close(srcfd);

	//阻塞I0实验
	write(STDOUT_FILENO,"阻塞实验开始\n",sizeof("阻塞实验开始\n"));
	memset(buff,0,sizeof(buff));
	read(STDIN_FILENO,buff,sizeof(buff));
	printf("read : %m\n");
	write(STDOUT_FILENO,buff,sizeof(buff));
	write(STDOUT_FILENO,"阻塞实验结束\n",sizeof("阻塞实验结束\n"));
	write(STDOUT_FILENO,"非阻塞实验开始\n",sizeof("非阻塞实验开始\n"));
	//非阻塞
	int fd = open("/dev/tty", O_RDONLY | O_NONBLOCK);
	printf("open : %m\n");
	printf("fd = %d\n", fd);
	int i = 0 ;
	for (i = 0; i < 10; ++i)
	{
		len = read(fd, buff, sizeof(buff));
		printf("len = %d\n",len );
    	if (len < 0) 
    	{
    		if (errno == EAGAIN) 
    		{
        		sleep(1); // 让出 CPU,避免CPU长时间空转
      		}   
      		else 
      		{
        		exit(1);
      		}   
    	}   
    	else 
    	{
    		write(STDOUT_FILENO,buff,sizeof buff);
    		memset(buff,0,sizeof buff);
    	}  
	}
	close(fd);

	printf("非阻塞实验结束\n");
	printf("fcntl实验\n");
	fd = open(argv[1],O_RDWR|O_APPEND);
	perror("open");
	if(fd < 0)
	{
		exit(0);
	}

	int flags = fcntl(fd,F_GETFL);
	perror("fcntl");
	if (flags < 0)
	{
		exit(-1);
	}

	if (flags & O_RDONLY) 
	{
		printf("O_RDONLY\n");
	}

	if (flags & O_WRONLY) 
	{
		printf("O_WRONLY\n");
	}

	if (flags & O_RDWR) 
	{
		printf("O_RDWR\n");
	}

	if (flags & O_NONBLOCK) 
	{
		printf("O_NONBLOCK\n");
	}
  
  	
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值