【APUE】3、第三章 文件I/O

第三章  文件I/O

 

3.1 引言


 

3.2 文件描述符

 

【APUE】3、第三章 文件I/O_第1张图片

 

 

3.3 函数open和openat

 【APUE】3、第三章 文件I/O_第2张图片



 

对于参数的选择,下面是必须指定一个且只能指定一个的,后面的是可选的

O_RDONLY

只读打开

O_WRONLY

只写打开

O_RDWR

读、写打开

O_EXEC

只执行打开

O_SEARCH

只搜索打开

O_APPEND

每次写时都追加到文件的尾端

O_CLOEXEC

吧FD_CLOEXEC常量设置为文件描述符标志

O_CREAT

若文件不存在就创建

O_DIRETORY

如果path引用的不是目录,则出错

O_EXCL

如果同时指定了O_CREAT,而文件已经存在则出错。

O_NOCTTY

如果path引用的是终端设备,则不将该设备分配作为此进程的控制终端。

O_NOFOLLOW

如果path引用的是一个符号链接,则出错

O_NONBLOCK

如果path引用的是一个FIFO、一个块特殊文件或一个字符特殊文件,则此选项为文件的本次打开操作和后续的I/O操作设置非阻塞方式

O_SYNC

使每次write等待物理I/O操作完成,包括由该write操作引起的文件属性更新所需的I/O。

O_TRUNC

如果此文件存在,而且为只写或读-写成功打开,则将其长度截断为0

O_TTY_INIT

如果打开一个还未打开的终端设备,设备非标准termios参数值

O_DSYNC

使每次write要等待物理I/O操作完成,但是如果该写操作并不影响读取刚写入的数据,则不需等待文件属性被更新

O_RSYNC

使每一个以文件描述符作为参数进行的read操作等待,直至所有对文件同一部分挂起的写操作都完成。

 

 

还有openat函数的fd参数的作用:

 



 

Openat函数的作用:

1、  让线程可以使用相对路径名打开目录中的文件

2、  可以避免time-of-check-to-time-of-use(TOCTTOU)错误。

 

 

3.4 函数create

 


 

 

 

3.5 函数close

 【APUE】3、第三章 文件I/O_第3张图片

 

3.6 函数lseek

 【APUE】3、第三章 文件I/O_第4张图片

 

/**
 * 功能:测试对其标准输入能否设置偏移量
 * 时间:2015年11月27日16:40:44
 * 作者:cutter_point
 */
#include "apue.h"
#include "error.c"

int main(void)
{
	//STDIN_FILENO表示标准输入,SEEK_CUR当前文件位置的漂移量+offset
	if(lseek(STDIN_FILENO, 0, SEEK_CUR) == -1)
	{
		printf("cannot seek\n");
	}//if
	else
	{
		printf("seek OK\n");
	}//else
	
	exit(0);
}

 


结果: 

 

 



【APUE】3、第三章 文件I/O_第5张图片

 

/**
 * 功能:创建一个具有空洞的文件
 * 时间:2015年11月27日17:14:28
 * 作者:cutter_point
 */
#include "apue.h"
#include "error.c"

#include 

char buf1[] = "abcdefghij";
char buf2[] = "ABCDEFGHIJ";

int main(void)
{
	int fd;	//文件标识号
	
	//这里FILE_MODE的作用是设定文件的权限,允许用户读写,组成员只读和其他用户只读权限也就是0644,-rw-r--r--
	if((fd = creat("file.hole", FILE_MODE)) < 0)
		err_sys("creat error");

	//write根据文件标识fd从buf1中读取10个字符到文件中
	if(write(fd, buf1, 10) != 10)
		err_sys("buf1 write error");

	//现在文件偏移量为10
	
	//重新设定文件偏移量
	if(lseek(fd, 16384, SEEK_SET) == -1)
		err_sys("buf2 write error");

	//文件偏移变为16384

	if(write(fd, buf2, 10) != 10)
		err_sys("buf2 write error");
	
	//文件偏移为16394

	exit(0);
}

 


结果: 

 


 

好,我们看看文件里面到底是什么数据

 

 

命令行中-c标志表示以字符方式打印文件内容

 

 【APUE】3、第三章 文件I/O_第6张图片

 


 

3.7 函数read

 

 【APUE】3、第三章 文件I/O_第7张图片

 

Ssize_t 返回字节记数的函数

 

【APUE】3、第三章 文件I/O_第8张图片

 

3.8 函数write

 



 

 

3.9 I/O的效率

 

/**
 * 功能:用read和write函数复制一个文件。
 * 时间:2015年11月27日17:40:24
 * 作者:cutter_point
 */
#include "apue.h"
#include "error.c"

#define BUFFSIZE 4096

int main(void)
{
	int n;
	char buf[BUFFSIZE];	//数据缓冲
	
	//从标准输入读入数据
	while((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0)
	{
		if(write(STDOUT_FILENO, buf, n) != n)
			err_sys("写入文件错误");
	}//while

	if(n < 0)
		err_sys("数据读取错误");	//如果我们最后写入的字节数小于0,而跳出的话,说明读取数据失败

	exit(0);
}


结果: 

 

 【APUE】3、第三章 文件I/O_第9张图片

 

【APUE】3、第三章 文件I/O_第10张图片

 

那么我们应该如何设定BUFFSIZE比较好呢?

 

 【APUE】3、第三章 文件I/O_第11张图片



 

 


 

3.10 文件共享

 

Unix系统支持在不同的进程间共享打开文件。

 

【APUE】3、第三章 文件I/O_第12张图片


【APUE】3、第三章 文件I/O_第13张图片

 

 

如果多进程打开同一文件的话

 

【APUE】3、第三章 文件I/O_第14张图片

 

 【APUE】3、第三章 文件I/O_第15张图片



 

3.11 原子操作

1.追加到一个文件

 

If(lseek(fd, OL, 2) < 0)//这里的2表示SEEK_END,也就是文件的长度加OL,到达文件的末尾

         Err_sys(“lseekerror”);

If(write(fd, buf, 100) != 100)

         Err_sys(“writeerror”);

 

以前的时候我们用这种方式吧数据添加到文件的末尾

但是:

 

【APUE】3、第三章 文件I/O_第16张图片

 

 

2. 函数pread和pwrite

 

【APUE】3、第三章 文件I/O_第17张图片

 

相当于给文件上锁

 

3.12 函数dup和dup2

 【APUE】3、第三章 文件I/O_第18张图片

【APUE】3、第三章 文件I/O_第19张图片

 

 

3.13 函数sync、fsync、fdatasync

 【APUE】3、第三章 文件I/O_第20张图片

 

3.14 函数fcntl

 【APUE】3、第三章 文件I/O_第21张图片

 

F_DUPFD

复制文件描述符fd。新文件描述符作为函数值返回。他是尚未打开的各描述符中大于或等于第三个参数值中各值得最小值

F_DUPFD_CLOEXEC

复制文件描述符,设置与新描述符关联的FD_CLOEXEC文件描述符标志的值,返回新文件描述符

F_GETFD

对应于fd的文件描述符标志作为函数值返回。

F_SETFD

对于fd设置文件描述符

F_GETFL

对应于fd的文件状态标志作为函数值返回。

【APUE】3、第三章 文件I/O_第22张图片

F_SETFL

将文件状态标志设置为第三个参数的值。可以更改的几个标志是:O_APPEND、O_NONBLOCK、O_SYNC、O_DSYNC、O_RSYNC、O_FSYNC和O_ASYNC

F_GETOWN

获取当前接收SIGIO和SIGURG信号的进程ID或进程组ID

F_SETOWN

设置接收SIGIO和SIGURG信号的进程ID或进程组ID。

 

 

实例:

 

/**
 * 功能:第一个参数指定文件描述符,并对该描述符打印其所选择的文件标志说明
 * 时间:2015年11月28日16:59:54
 * 作者:cutter_point
 */
#include "apue.h"
#include "error.c"

#include 

int main(int argc, char *argv[])
{
	int val;	//用来获取文件的对应fd的文件描述符标志

	if(argc != 2)
		err_quit("少了文件描述符");

	if((val = fcntl(atoi(argv[1]), F_GETFL, 0)) < 0)
		err_sys("fcntl错误的fd:%d", atoi(argv[1]));

	switch(val & O_ACCMODE)
	{
		case O_RDONLY:
			printf("只读");
			break;
		case O_WRONLY:
			printf("只写");
			break;
		case O_RDWR:
			printf("读写");
			break;
		default:
			err_dump("未知描述符");
	}//switch

	if(val & O_APPEND)
		printf(", append");

	if(val & O_NONBLOCK)
		printf(", nonblocking");

	if(val & O_FSYNC)
		printf(", synchronous writes");

	//O_FSYNC两个都是等待写完成,但是O_FSYNC是仅仅FreeBSD和Mac OS X
	#if !defined(_POSIX_C_SOURCE) && defined(O_FSYNC) && (O_FSYNC != O_SYNC)
		if(val & O_FSYNC)
			printf(", synchronous writes");
	#endif

	putchar('\n');
	exit(0);
}


结果: 

 【APUE】3、第三章 文件I/O_第23张图片

5<>temp.foo表示在文件描述符5上打开文件temp.foo以供读写

 

 


/**
 * 功能:对一个文件描述符设置一个或多个文件状态标志的函数
 * 时间:2015年11月28日17:17:46
 * 作者:cutter_point
 */
#include "apue.h"
#include "error.c"

#include 

void set_fl(int fd, int flags)
{
	int val;

	if((val = fcnl(fd, F_GETFL, 0)) < 0)
		err_sys("fcntl F_GETFL error");

	val |= flags;

	if(fcntl(fd, F_SETFL, val) < 0)
		err_sys("fcntl F_SETFL error");
}

  

3.15 函数iocti

 【APUE】3、第三章 文件I/O_第24张图片



【APUE】3、第三章 文件I/O_第25张图片

 

 

 

具体使用,我们日后详谈

 

3.16  dev/fd

 【APUE】3、第三章 文件I/O_第26张图片

 

这里打开0号标志,返回一个新的描述符。

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(Unix环境高级编程)