c语言文件IO库函数——APUE学习笔记(1)

大多数函数只需要五个函数实现IO操作:open, read, write, lseek, close.


一. 文件描述符:

文件描述符时一个非负整数(0~OPEN_MAX - 1).当打开现有文件或者创建新文件时,内核向进程返回一个文件描述符一边标示一个文件。
内核文件描述符要区别于shell文件描述符:shell内定了幻数0, 1, 2分别表示标准输入,标准输出和标准错误。

二. 文件操作函数:


1.open或openat:


(1). 打开文件,成功返回文件描述符,失败返回-1.

#include 

int open(const char *path, int oflag, ... /*mode_t mode */);
int openat(int fd, const char *path, int oflag, ... /*mode_t mode */);

(2). 参数:

a. path表示文件路径;
b. oflag用来说明该函数的多个选项,如:O_RDONLY, O_WRONLY, O_RDWR分别表示只读,只写和可读写,而O_CREAT选项表示当打开文件不存在时创建这个文件,O_DIRECTORY选项表示如果path应用的不是目录则出错。这些选项都可以通过man page查询获得。
c. …参数:ISO C用这种方法表示剩余参数为可变参数,即在需要时可以变参。

(3). 文件描述符fd参数将open和openat区分开来:

a. 当path指定的为绝对路径时,fd参数被忽略,两函数相等。
b. 怕path指出相对路径名时,fd参数相对路径名在文件系统中的开始地址。fd参数是通过打开相对路径名所在的目录来获取的。
c. path参数指定了相对路径名,fd参数具有特殊值AT_FDCWD。在这种情况下路径名在当前工作目录中获取,openat和open类似。

2.creat


(1). 创建只写文件,成功返回只写文件描述符,失败返回-1.


#include 

int creat(const char *path, mode_t mode);

此函数等效于:

open(path, O_RDWR|O_CREAT|O_TRUNC, mode);

(2). 参数:

a. path为路径
b. mode为权限模式

(3). creat函数只能以只写方式打开所创建的文件。早期版本中使用该函数,现在多用open函数代替

open(path, O_RDWR|O_CREAT|O_TRUNC, mode);

3.close

(1). 关闭文件,成功返回0,出错返回-1.

#include 

int close(int fd);

(2). 当文件关闭同时会释放所有加在该文件上的记录锁。

(3). 当一个文件终止时,内核会自动关闭它所打开的所有文件。所以close函数一般不现式使用。

4.lseek

(0). 文件偏移量:通常是一个非负整数,用以度量从文件开始处计算的字节数。

#include 

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

(1). 设置文件偏移量,成功返回返回新的文件偏移量,失败返回-1.

(2). 参数:

a. offset参数解释和whence值有关:
-> whence为SEEK_SET时,文件偏移量将被设为距文件开始offset个字节。
-> whence为SEEK_CUR时,文件偏移量将被设为当前偏移量加上offset(offset正负都可)。
-> whence为SEEK_END时,文件偏移量将被设为文件长度加offset(offset正负都可)。

(3). 管道,FIFO, 网络套接字不可设置偏移量,若对其操作,返回-1,errno为ESPIPE。

(4). 一般情况文件的偏移量为一个非负整数,但是某些特殊设备时允许负的偏移量的,so~,判断文件偏移量是否设置成功应该看看他的lseek返回值是否为-1,而不是判断它是不是负数。

(5). lseek仅仅时将文件偏移量记录在内核中,他本身并不引起IO操作,这个偏移量的存在只是给下一次的读和写操作的。

(6). 文件空洞:文件偏移量时可以大于文件当前长度的,这样如果得到偏移量后的执行一次写操作,写的位置和文件开头就存在了一片空白区,这段区域被字符0填满,称之为空洞,(空洞不要求占用磁盘存储区)。

5.read

(1). 读文件,返回读到的字节数,弱国已经读到文件末尾了,则返回0,失败返回-1。

#include 

ssize_t read(int fd, void *buf, size_t nbytes);

(2). 在下述情况下,函数实际读到的字节数少于要求读到的字节数。

a. 要求读的大小大于文件本身大小时:
在还没读到文件要求大小时文件已经读到末尾了.例如:如文件只有30字节,而要求 读100字节,这样read函数将返回30,下次调用read时它将返回0.

b. 从终端读设备读时:
一次只读一行,和标准输出按行刷新对应.

c. 从网络读数据时:
网络缓存机制导致返回值小于要求读的大小.

d.从管道读取数据时:
返回实际管道可用数据.

e. 从面向记录设备读时:
一次只能读一条记录.

f. 读过程中遇到信号中断时:
返回实际读到的数据.

g. 返回值类型(ssize_t)为带符号整数:
为确保函数可以返回正整数字节,0(到文件尾),-1(出错).

6.函数write.

(1). 写入函数,向文件描述符为fd的已打开文件中写数据,成功返回写入字节数,出错返回-1.

(2). write函数的返回值通常与nbytes值相同,否则表示出错.

(3). 出错原因常见为:

a.磁盘已满.
b.超过给定进程的文件长度限制.

(4).普通文件执行写使用write时,写操作是从文件当前偏移量处开始.

在文件打开时设置追加属性O_APPEND,这样在每次写操作时文件偏移量就会被设置在文件末尾处,写成功后,文件偏移量增加写入文件长度.

例:用read和write函数实现简单函数复制:

#include  //apue.h头文件中包含有write,read以及基本操作头文件

#define BUFFSIZE 4096

int main(int argc, char **argv)
{
    int n;
    char buf[BUFFSIZE];

    //从标准输入读文件,每次读BUFFSIZE个字节,读到buf数组中
    while((n == read(STDIN_FILENO, buf, BUFFSIZE)) > 0){
        //read正确时,写入文件到标准输出中,一次写n个字节
        if(write(STDOUT_FILENO, buf, n) != n){
            err_sys("write error!");
        }
    }

    //read函数返回-1时,输出错误信息并退出
    if(n < 0){
        err_sys("read error!");
    }

    exit(0);
}

你可能感兴趣的:(c语言文件IO库函数——APUE学习笔记(1))