UNIX环境高级编程(第三版)学习笔记(三、文件I/O之一)

时间:2022-05-22 15:14:40

1.文件描述符

对于内核而言,所有打开的文件都通过文件描述符来引用,他是一个非负数。当打开一个文件或者创建一个文件的时候,内核向进程返回一个文件描述符,opencreatreadwrite等函数是用文件描述符作为参数的,在标准UNIX中,012是被预先设置好的,一次分别是标准标准输入,标准输出,标准出错。但是按照惯例,应该用符号代替它们,分别表示-STDIN_FILENOSTDOUT_FILENOSTDERR_FILENO,这几个常量都在unistd.h头文件中定义,

PS:文件描述符的变化范围是0OPEN_MAX-1

1.函数openopenat

#include<unistd.h>

intopen (const char *path,int oflag, ... /*mode_tmode*/);

intopenat(int fd, const char *path, int oflag, .../*mode_tmode*/);

成功返回文件描述符,失败返回-1

path是要打开的文件路径或者名子,oflag个选项的组合,

分别是:O_RDONLY(只读)O_WRONLY(只写)O_RDWR(读写)

以上三种比较常用。还有多种参考书62

两个函数的区别fd参数把openopenat函数区分开

1)如果path指定的是绝对路径,在这种情况下fd被忽略,二者相等。

2path参数指定的是相对路径名,fd参数指定的是相对路径名在文件系统中的开始地址,fd参数是通过打开先谷地路径名所在的目录所获取的。

3path参数指定了相对路径名,fd参数具有特殊值AT_FDCWD。在这种情况下,路径名称在当前工作目录中获取。openat函数在操作上与open函数类似。

openat函数是POSIX版本新增加的函数之一。希望解决两个问题,第一,可以通过相对路径名打开目录中的文件,而不再是智能打开当前工作目录,线程的方面会用到此处。

第二可以避免TOCTTOU错误(了解)

2.函数creat

#include<unistd.h>

intcreat (const char *path, mode_t mode);

成功返回文件描述符,失败返回-1

此函数等效与,open(path , O_WRONLY | O_CREAT | O_TRUNC, mode);

creat不推荐使用,因为他是有一个缺陷的,他以只写方式打开创建的文件,最好使用open函数来创建文件。因为操作可以控制。

3.函数close

可以调用close函数来关闭一个打开的文件

#include<unistd.h>

intclose (int fd);

成功返回0,失败返回-1

用完了的文件要记得关闭哦。

记住,当一个进程终止的时候,内核自动关闭它所有的打开文件,很多程序都利用这一功能而不显式的关闭打开文件。

4.函数lseek

每一个打开的文件都有一个与其相关联的“当前文件偏移量”。它通常是一个非负整数,用以度量从文件开始处计算的字节数。

#include<unistd.h>

off_tlseek(int fd, off_t offset, int whence);

成功返回文件的偏移量。失败则返回-1

offset参数和whence参数是有关联的。

*whence参数是SEEK_SET,则该文件的偏移量设置为距文件开始处offset个字节。

*whence参数是SEEK_CUR,则该文件的偏移量设置为当前值+offset个字节。offset可以为正,可以为负

*whence参数是SEEK_END,则该文件的偏移量设置为文件长度+offset个字节。offset可以为正,可以为负



可以用下列方式确定打开文件的当前偏移量:

off_t currpos;

currpos= lseek(fd, 0 ,SEEK_CUR)

这种方法还可以用来确定一个文件是否可以被设置偏移量,如果文件描述符指向的是一个管道,FIFO或者网络套接字,则lseek返回-1并且将error设置为ESPIPE



实例:测试对其标准输入能否设置偏移量

#include“apue.h”

intmain (void) {

if(lseek(STDIN_FILENO0SEEK_CUR)== -1)

printf(“cannot seek”);

else

printf(“seekOK \n”);

exit(0);

}

$./a.out < /etc/passwd (这是一个文件,将里面的内容输入到程序中可见可以设置偏移量)

seekOK

$cat < /etc/passwd | ./a.out ( |是一个管道就是将cat出来的东东输入到程序中,可见不可以设置偏移量)

cannotseek

$./a.out< /var/spool/cron/FIFO (可见,FIFO文件不可以设置偏移量)

cannnotseek



PS:通常文件偏移量可以为负,所以测试是否出错的时候请不要测试是否小于0,二要测试是否等于-1

文件偏移量可以大于文件,但是在下一次写操作的时候会在文件中构成一个空洞。空洞是不占用磁盘块的

5.函数readwrite

调用read函数从打开的文件中读取数据

#include<unistd.h>

ssize_tread(int fd,void *buf. size_t nbytes);

成功返回读到的字节数,失败返回-1

记住,每一次读取都会使文件偏移量增加,增加数和读取数大小有关,读取多少增加多少。

返回值0表示在文件尾端

#include<unistd.h>

ssize_twrite(int fd,void *buf. size_t nbytes);

二者差不多,一个是写,一个是读取。读取出错原因是磁盘写满,或者超过了一个给定进程的文件长度限制。

实例:只使用readwtite函数复制一个文件

#include“apue.h”

#defineBUFFSIZE 4096

intmain (void) {

intn;

charbuf[BUFFSIZE];

while(n = read(STDIN_FILENO, buf, BUFFSIZE) > 0)

if(write (STDIN|_FILENO, buf, n) != n)

err_sys(“writeerror”); //apue.h自带的错误处理函数

if (n < 0)

err_sys(“readerror”);

exit(0);

}