> For the complete documentation index, see [llms.txt](https://xiaoxiami.gitbook.io/linux-server/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://xiaoxiami.gitbook.io/linux-server/wen-jian-cao-zuo/linux-di-ceng/chang-yong-wen-jian-cao-zuo-han-shu.md).

# 常用文件操作函数

## open()函数：打开文件函数

**头文件：**`#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>`

**函数定义：**  <br>

```
int open(const char * pathname, int flags);
int open(const char * pathname, int flags, mode_t mode);
```

> open()函数有两种调用模式：当不指定mode参数时，表示打开一个现有的文件（前提是文件必须得存在，否则open将出错返回）;当指定mode参数时，表示若开发的文件不存在则先创建它，然后再打开，而 参数mode表示所创建文件的权限。

**函数说明：**

参数 pathname ：是一个字符串指针，指向需要打开（或创建）文件的绝对路径名或相对路径名.

参数 flags：用于描述文件的打开方式，以下表中这些常数定义在`fcntl.h`头文件中。

> flags的值可由表中取值的逻辑或得到。其中O\_RDONLY、 OWRONLY 、ORDWR 这三个参数只能指定其中一个，其他的常数则是可选择的。

|      参数值     | 说明                                                                                                               |
| :----------: | ---------------------------------------------------------------------------------------------------------------- |
|   O\_RDONLY  | 以只读方式打开文件                                                                                                        |
|   O\_WRONLY  | 以只写方式打开文件                                                                                                        |
|    O\_RDWR   | 以可读写方式打开文件. 上述三种旗标是互斥的, 也就是不可同时使用, 但可与下列的旗标利用OR(\|)运算符组合.                                                        |
|   O\_CREAT   | 若欲打开的文件不存在则自动建立该文件.                                                                                              |
|    O\_EXCL   | 如果O\_CREAT 也被设置, 此指令会去检查文件是否存在. 文件若不存在则建立该文件, 否则将导致打开文件错误. 此外, 若O\_CREAT 与O\_EXCL 同时设置, 并且欲打开的文件为符号连接, 则会打开文件失败. |
|   O\_NOCTTY  | 如果欲打开的文件为终端机设备时, 则不会将该终端机当成进程控制终端机.                                                                              |
|   O\_TRUNC   | 若文件存在并且以可写的方式打开时, 此旗标会令文件长度清为0, 而原来存于该文件的资料也会消失.                                                                 |
|   O\_APPEND  | 当读写文件时会从文件尾开始移动, 也就是所写入的数据会以附加的方式加入到文件后面.                                                                        |
|  O\_NONBLOCK | 以不可阻断的方式打开文件, 也就是无论有无数据读取或等待, 都会立即返回进程之中.                                                                        |
|   O\_NDELAY  | 同O\_NONBLOCK.                                                                                                    |
|    O\_SYNC   | 以同步的方式打开文件.                                                                                                      |
|  O\_NOFOLLOW | 如果参数pathname 所指的文件为一符号连接, 则会令打开文件失败.                                                                             |
| O\_DIRECTORY | 如果参数pathname 所指的文件并非为一目录, 则会令打开文件失败。**注：**&#x6B64;为Linux2. 2 以后特有的旗标, 以避免一些系统安全问题.                               |

参数 mode：用于指定所创建文件的权限。

> 参数mode 的类型 mode\_t 实际上是一个无符号短整型数，定义在 include/linux/types.h

**参数mode 则有下列数种组合, 只有在建立新文件时才会生效, 此外真正建文件时的权限会受到umask 值所影响, 因此该文件权限应该为 (mode-umaks).**

|          权限         |   值   | 说明                      |
| :-----------------: | :---: | ----------------------- |
|       S\_IRWXU      | 00700 | 代表该文件所有者具有可读、可写及可执行的权限. |
|  S\_IRUSR 或S\_IREAD | 00400 | 代表该文件所有者具有可读取的权限        |
| S\_IWUSR 或S\_IWRITE | 00200 | 代表该文件所有者具有可写入的权限.       |
|  S\_IXUSR 或S\_IEXEC | 00100 | 代表该文件所有者具有可执行的权限.       |
|       S\_IRWXG      | 00070 | 代表该文件用户组具有可读、可写及可执行的权限. |
|       S\_IRGRP      | 00040 | 代表该文件用户组具有可读的权限.        |
|       S\_IWGRP      | 00020 | 代表该文件用户组具有可写入的权限.       |
|       S\_IXGRP      | 00010 | 代表该文件用户组具有可执行的权限.       |
|       S\_IRWXO      | 00007 | 代表其他用户具有可读、可写及可执行的权限.   |
|       S\_IROTH      | 00004 | 代表其他用户具有可读的权限           |
|       S\_IWOTH      | 00002 | 代表其他用户具有可写入的权限.         |
|       S\_IXOTH      | 00001 | 代表其他用户具有可执行的权限.         |

另外，为方便在程序中使用，“fcntl.h”头文件中还定义了三个常用的逻辑组合

![](/files/-LfnTGTrq1ml9DvOqfJm)

**返回值：**&#x82E5;所有欲核查的权限都通过了检查则返回0 值, 表示成功, 只要有一个权限被禁止则返回-1.

**错误代码：**

|     错误代码     | 说明                                             |
| :----------: | ---------------------------------------------- |
|    EEXIST    | 参数pathname 所指的文件已存在, 却使用了O\_CREAT 和O\_EXCL 旗标. |
|    EACCESS   | 参数pathname 所指的文件不符合所要求测试的权限.                   |
|     EROFS    | 欲测试写入权限的文件存在于只读文件系统内.                          |
|    EFAULT    | 参数pathname 指针超出可存取内存空间.                        |
|    EINVAL    | 参数mode 不正确.                                    |
| ENAMETOOLONG | 参数 pathname 太长.                                |
|    ENOTDIR   | 参数pathname 不是目录.                               |
|    ENOMEM    | 核心内存不足.                                        |
|     ELOOP    | 参数pathname 有过多符号连接问题.                          |
|      EIO     | I/O 存取错误.                                      |

## create()函数：创建文件函数

**头文件：**`#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>`

**函数定义：** `int create(const char *pathname, mode_t mode)`**;**

**函数说明：**&#x521B;建一个新的文件，并以**只写方式**打开该文件。

**返回值：**&#x5F53;有错误发生时则返回-1, 错误代码存入errno 中, 而文件读写位置则无法预期.

**附加说明：**&#x53C2;数pahtname 和mode 的含义与open()函数相同。所以,create函数等效于

```
open(pathname, O_WRONLY|OCREAT|O_TRUNC,mode);
```

> create函数的一个不足之处是它以只写方式打开所创建的文件。

## read()函数：读文件函数(由已打开的文件读取数据)

**头文件：**`#include <unistd.h>`

**函数定义：**`ssize_t read(int fd, void *buf, size_t count);`

**函数说明：**&#x72;ead()会把参数fd 所指的文件传送count 个字节到buf 指针所指的内存中. 若参数count 为0, 则read()不会有作用并返回0. 返回值为实际读取到的字节数, 如果返回0, 表示已到达文件尾或是无可读取的数据,此外文件读写位置会随读取到的字节移动.

**附加说明：**

如果顺利 read()会返回实际读到的字节数, 最好能将返回值与参数count 作比较, 若返回的字节数比要求读取的字节数少, 则有可能读到了文件尾

**返回值：若成功，函数返回去到的字节数，**&#x5F53;有错误发生时则返回-1, 错误代码存入errno 中, 而文件读写位置则无法预期.

**错误代码：**

|  错误代码  | 说明                                       |
| :----: | ---------------------------------------- |
|  EINTR | 此调用被信号所中断.                               |
| EAGAIN | 当使用不可阻断I/O 时(O\_NONBLOCK), 若无数据可读取则返回此值. |
|  EBADF | 参数fd 非有效的文件描述词, 或该文件已关闭.                 |

## write()函数：写文件函数

**头文件：**`#include <unistd.h>`

**定义函数：**`ssize_t write (int fd, const void *buf, size_t count);`

**函数说明：**&#x77;rite()会把参数buf 所指的内存写入count 个字节到参数fd 所指的文件内. 当然, 文件读写位置也会随之移动.

buf参数是一个指向缓冲区的指针，该缓冲区存放将要写入文件的数据;

count参数表示本次操作将要写入文件的数据的字节数。

**返回值：**&#x5982;果顺利write()会返回实际写入的字节数. 当有错误发生时则返回-1, 错误代码存入errno 中.

**错误代码：**

|  错误代码  | 说明                                        |
| :----: | ----------------------------------------- |
|  EINTR | 此调用被信号所中断.                                |
| EAGAIN | 当使用不可阻断I/O 时 (O\_NONBLOCK), 若无数据可读取则返回此值. |
|  EADF  | 参数fd 非有效的文件描述词, 或该文件已关闭.                  |

## close()函数：关闭函数

**头文件：**`#include <unistd.h>`

**定义函数：**`int close (int fd);`

**函数说明：**&#x5F53;使用完文件后若已不再需要则可使用 close()关闭该文件, 二close()会让数据写回磁盘, 并释放该文件所占用的资源. 参数fd 为先前由open()或creat()所返回的文件描述词.

返回值：若文件顺利关闭则返回0, 发生错误时返回-1.

**错误代码：**&#x45;BADF 参数fd 非有效的文件描述词或该文件已关闭.

**附加说明：**&#x867D;然在进程结束时, 系统会自动关闭已打开的文件, 但仍建议自行关闭文件, 并确实检查返回值.

## lseek()函数：移动文件的读写位置

**头文件：**`#include <sys/types.h> #include <unistd.h>`

**定义函数：**`off_t lseek(int fd, off_t offset, int whence);`

**函数说明：**&#x20;

每一个已打开的文件都有一个读写位置,它是一个非负整数，用以度量从文件开始处计算的字节数。 当打开文件时通常其读写位置是指向文件开头, 若是以附加的方式打开文件(如O\_APPEND), 则读写位置会指向文件尾. 当read()或write()时, 读写位置会随之增加,lseek()便是用来控制该文件的读写位置.

参数fd 为已打开的文件描述符,

参数offset 为根据参数whence来移动读写位置的位移数.（参数offset表示位移量的大小，单位为字节。对参数offset的解释与参数whence的取值有关）

参数 whence 为下列其中一种:

```
SEEK_SET 参数offset 即为新的读写位置.

SEEK_CUR 以目前的读写位置往后增加offset 个位移量.

SEEK_END 将读写位置指向文件尾后再增加offset 个位移量. 当whence 值为SEEK_CUR 或　SEEK_END 时, 参数offet 允许负值的出现.
```

下列是教特别的使用方式:

1\) 欲将读写位置移到文件开头时:

```
off_t = currpos;
currpos = lseek(int fildes, 0, SEEK_SET);
```

2\) 欲将读写位置移到文件尾时:

```
off_t = currpos;
currpos = lseek(int fildes, 0, SEEK_END);
```

3\) 想要取得目前文件位置时:

```
off_t = currpos;
currpos = lseek(int fildes, 0, SEEK_CUR);
```

**返回值：**&#x5F53;调用成功时则返回目前的读写位置, 也就是距离文件开头多少个字节. 函数的返回值为off\_t类型，实际上是一个长整形数，若有错误则返回-1, errno 会存放错误代码.

**附加说明：**&#x4C;inux 系统不允许lseek()对tty 装置作用, 此项动作会令lseek()返回ESPIPE.

### 示例

#### 示例1:

程序首先以只写方式打开（文件不存在则创建）一个文件，文件名由用户从终端输入，然后打印出系统分类的文件描述符，操作完毕后关闭文件。

```c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>

#define FLAGS O_WRONLY|O_CREAT|O_TRUNC
// 定义flags: 只写，文件不存在则创建，文件长度截断为0
#define MODE S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH
// 创建文件的权限:用户读/写、执行，同组读、执行，其他用户给读、执行，

int main(void)
{
    int fd; // 文件描述符
    char pathname[30];  // 存放要打开（或创建）文件的绝对路径名或相对路径名
    printf("Input the pathname[<30 strings]:"); //输入路径名，小于30个字符
    fgets(pathname, 30, stdin);
    if((fd=open(pathname,FLAGS,MODE))==-1){ //调用open()函数
        printf("error,open file failed!:\n");
        exit(1);  // 出错退出
    }
    printf("OK,open file success!\n");
    printf("fd=%d\n",fd);
    if(close(fd)==-1){
        printf("error,close file failed!:\n");
        exit(1);  // 出错退出
    }
    printf("OK,close file success!\n");
    return 0;
}
```

运行程序：

```
Input the pathname[<30 strings]:/tmp/test
OK,open file success!
fd=3
OK,close file success!
```

#### 示例2:

利用lseek()函数来获取文件的长度。程序中首先使用open()函数打开由用户输入的文件名，然后使用lseek 返回当前文件的位移量，由于将lseek的第三个参数whence设置为`SEEK_END`,而第二个参数offset设置为０，这样实际上lseek返回的是以字节为单位的文件内容的长度。

```c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>

#define FLAGS O_WRONLY|O_CREAT
// 定义flags: 读／写方式，文件不存在则创建
#define MODE S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH
// 创建文件的权限:用户读/写、执行，同组读、执行，其他用户给读、执行，

int main(void)
{
    int fd; // 文件描述符
    off_t currpos; // 定义变量　currpos的数据类型为off_t
    char pathname[30]; // 存放要打开（或创建）文件的绝对路径名或相对路径名
    printf("Input the pathname[<30 strings]:"); //输入路径名，小于30个字符
    fgets(pathname, 30, stdin);
    if((fd=open(pathname,FLAGS,MODE))==-1){ //调用open()打开文件
        printf("error,open file failed!:\n");
        exit(1); // 出错退出
    }
    printf("OK,open file success! fd=%fd\n",fd);
    if((currpos = lseek(fd,0,SEEK_END))==-1){ // 获取当前文件的位移量
        printf("error,lseek file failed!:\n");
        exit(1); // 出错退出
    }
    printf("Current offset is %d\n", currpos);
    if(close(fd)==-1){
        printf("error,close file failed!:\n");
        exit(1); // 出错退出
    }
    printf("OK,close file success!\n");
    return 0;
}
```

运行程序：

```c
Input the pathname[<30 strings]:/tmp/test
OK,open file success! fd=0.000000d
Current offset is 8
OK,close file success!
```

#### 示例3:

文件读写操作。程序中先打开/tmp/test目录下的test文件（没有该文件则创建），接着读取其中的内容，然后提示用户从终端输入一些数据，并调用write()函数将用户输入的内容写入test文件中，最后使用read()函数读取文件的内容并打印数据。

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

#define FILENAME "/tmp/test1/test" // 要进行读写操作的文件
#define SIZE 80
#define FLAGS O_RDWR|O_CREAT|O_APPEND
// 定义flags: 以读/写方式打开文件，文件不存在则创建，向文件条件内容时从文件尾开始写
#define MODE S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH
// 创建文件的权限:用户读/写、执行，同组读、执行，其他用户给读、执行，

int main(void)
{
    int count;
    int fd; // 文件描述符
    off_t currpos; // 定义变量　currpos的数据类型为off_t
    char buffer[SIZE]; // 读／写缓冲区
    if((fd=open(FILENAME,FLAGS,MODE))==-1){ //调用open()打开文件
        printf("error,open file failed!:\n");
        exit(1); // 出错退出
    }
    printf("OK,open file success! fd=%fd\n",fd);
    if((count = read(fd,buffer,SIZE))==-1){ // 获取当前文件的位移量
        printf("error,lseek file failed!:\n");
        exit(1); // 出错退出
    }
    printf("Before write,read [%d] string from file:",count);
    puts(buffer);
    printf("Begin write,get buffer form stdin:");
    gets(buffer);
    if((count=write(fd,buffer,strlen(buffer)))==-1){
        printf("error,write file failed!:\n");
        exit(1); // 出错退出
    }
    printf("OK,write [%d] string to file!\n",count);
    if((count=read(fd,buffer,SIZE))==-1){
        printf("error,read file failed!:\n");
        exit(1); // 出错退出
    }
    printf("After write,read [%d] string from file!\n",count);
    puts(buffer);
    return 0;
}
```

运行程序：

```
OK,open file success! fd=0.000000d
Before write,read [2] string from file:aa��
Begin write,get buffer form stdin:hello
OK,write [5] string to file!
After write,read [0] string from file!
hello
```
