# 常用文件操作函数

## 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
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://xiaoxiami.gitbook.io/linux-server/wen-jian-cao-zuo/linux-di-ceng/chang-yong-wen-jian-cao-zuo-han-shu.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
