文章目录

    • 一、linux文件权限
      • 1.1 文件描述符
      • 1.2 文件描述符的范围和默认值
      • 1.3 打开文件和文件描述符
      • 1.4 标准文件描述符
      • 1.5 文件描述符的重定向和关闭
      • 1.6 I/O 操作
      • 1.7 使用文件描述符进行进程通信
      • 1.8 资源限制
    • 二、C语言文件读写
      • 2.1 open 函数
      • 2.2 fopen函数
      • 2.3 flags参数详解
      • 2.4 lseek 函数
      • 2.5 fopen和fwrite函数
      • 2.5 open函数和fopen函数区别
      • 2.6 主要区别总结
    • 三、综合运用(open函数)
      • 3.1 获取文件长度
      • 3.2 追加写入
      • 3.3 覆盖写入
      • 3.4 创建文件
      • 3.5 复制文件操作
      • 3.6 查找文件中的字符串,并修改
    • 四、综合运用(fopen函数)
      • 4.1 读取文件

一、linux文件权限

字符表示法 二进制 十进制说明r - - 1004 仅可读- w - 0102 仅可写- - x 0011 仅可执行r w - 1106 可读可写r - x 1015 可读可执行- w x 0113 可写可执行r w x 1117 可读可写可执行- - - 0000 无权限

1.1 文件描述符

在 Linux 系统中,文件描述符是用于访问文件、设备、套接字和其他 I/O 资源的抽象概念。它是一个非负整数,用于唯一标识一个打开的文件或者 I/O 通道。Linux 将所有的 I/O 资源(包括文件、管道、套接字等)都视为文件,并通过文件描述符进行访问。

下面是文件描述符的一些关键特性和使用情况:

1.2 文件描述符的范围和默认值

  • 文件描述符的范围通常是从 0 开始递增的整数。0、1 和 2 分别是标准输入、标准输出和标准错误输出的文件描述符。在大多数情况下,系统会将第一个打开的文件赋予文件描述符 3,然后依次递增分配给其他打开的文件或者 I/O 通道。

1.3 打开文件和文件描述符

  • 使用系统调用如 open()socket()pipe() 等来打开文件或创建 I/O 通道时,会返回一个文件描述符。
  • 例如,open() 打开文件后返回一个文件描述符,你可以使用这个描述符进行读取、写入或其他操作。

1.4 标准文件描述符

  • 0:标准输入(stdin)
  • 1:标准输出(stdout)
  • 2:标准错误输出(stderr)

1.5 文件描述符的重定向和关闭

  • 可以使用系统调用如 dup()dup2() 来复制文件描述符或者将一个文件描述符重定向到另一个文件描述符上。
  • 使用 close() 可以关闭一个文件描述符,释放系统资源。关闭文件描述符后,相应的文件或 I/O 通道不再被该描述符引用。

1.6 I/O 操作

  • 通过文件描述符,可以进行读取、写入、定位文件指针和其他 I/O 操作。
  • 例如,read()write() 等系统调用使用文件描述符来执行对文件的读取和写入操作。

1.7 使用文件描述符进行进程通信

  • 文件描述符在进程间通信(IPC)中扮演重要角色,比如通过管道、套接字、匿名管道等进行进程间通信时,文件描述符的传递和共享是常见的做法。

1.8 资源限制

  • 系统对文件描述符数量有限制,可通过 ulimit 命令查看和设置文件描述符的数量限制。

文件描述符的使用对于在 Linux 系统下进行 I/O 操作和进程通信非常重要。它提供了一种标准化的方法来访问不同类型的 I/O 资源,简化了对文件和其他 I/O 设备的操作。

二、C语言文件读写

int open(const char *pathname, int flags);

2.1 open 函数

open 函数用于打开一个文件,并返回一个文件描述符(file descriptor),这个描述符可以用于后续的文件读写操作。

语法

#include #include #include int open(const char *pathname, int flags);int open(const char *pathname, int flags, mode_t mode);
  • pathname 是要打开的文件的路径名。

  • flags 是打开文件时的标志,它可以指定文件的打开方式(例如只读、只写、追加等)。一些常用的标志包括:

    • O_RDONLY: 只读方式打开文件
    • O_WRONLY: 只写方式打开文件
    • O_RDWR: 读写方式打开文件
    • O_CREAT: 如果文件不存在则创建文件
    • O_APPEND: 追加方式打开文件
    • 等等(可以使用按位或 | 连接多个标志)。
  • mode 是一个权限参数,仅在使用 O_CREAT 标志创建文件时才需要。它指定了文件的权限,比如 0644

返回值

  • 如果成功,open 函数返回一个非负整数的文件描述符,可以用于后续的文件 I/O 操作。
  • 如果失败,返回值为 -1,并设置全局变量 errno 表示出错的原因。

示例

#include #include #include int main() {int fd;fd = open("example.txt", O_WRONLY | O_CREAT, 0644);if (fd == -1) {perror("open");return 1;}// 可以在这里进行文件写操作等close(fd);return 0;}

2.2 fopen函数

fopen() 是 C 语言标准库 中的一个函数,用于打开文件。它提供了一种跨平台的文件操作方式,并返回一个文件指针,以便对文件进行读取、写入和其他操作。

原型:

FILE *fopen(const char *filename, const char *mode);
  • filename 是要打开的文件的路径和名称。
  • mode 是以何种方式打开文件,例如读取、写入、追加等,以字符串形式传入。

常见的打开模式:

  • "r":只读方式打开文件,文件必须存在。
  • "w":写入方式打开文件,如果文件不存在则创建,如果文件存在则清空内容。
  • "a":追加方式打开文件,如果文件不存在则创建,在文件末尾追加写入内容。
  • "r+":读写方式打开文件,文件必须存在。
  • "w+":读写方式打开文件,如果文件不存在则创建,如果文件存在则清空内容。
  • "a+":读写方式打开文件,如果文件不存在则创建,在文件末尾追加读写内容。

返回值:

  • fopen() 成功打开文件时,返回指向 FILE 结构的指针,用于后续对文件的操作。如果打开文件失败,则返回 NULL

示例:

#include int main() {FILE *filePointer;char buffer[100];filePointer = fopen("example.txt", "r"); // 以只读方式打开文件if (filePointer == NULL) {printf("File opening failed.\n");} else {printf("File opened successfully.\n");// 读取文件内容while (fgets(buffer, sizeof(buffer), filePointer) != NULL) {printf("%s", buffer);}fclose(filePointer); // 关闭文件}return 0;}

在此示例中,fopen() 以只读方式打开文件 “example.txt”,然后使用 fgets() 逐行读取文件内容,并将读取的内容输出到控制台。最后使用 fclose() 关闭文件。

2.3 flags参数详解

  1. O_CREAT:在文件打开过程中创建新文件
  2. O_RDONLY:以只读方式打开文件。
  3. O_WRONLY:以只写方式打开文件。
  4. O_RDWR:以读写方式打开文件。
  5. O_APPEND:在文件末尾追加数据,而不是覆盖现有内容。
  6. O_TRUNC:如果文件已经存在,将其截断为空文件。
  7. O_EXCL:与 O_CREAT 一起使用时,如果文件已经存在,则 open() 调用将失败。
  8. O_SYNC:使文件写操作变为同步写入,即将数据立即写入磁盘。
  9. O_NONBLOCK:以非阻塞方式打开文件,即使无法立即进行读写操作也不会被阻塞。

当文件为空的时候,文件指针初始化指向0的位置,随着写入,文件指针会落到最后一个字符的后面。当文件描述符被关闭后,重新使用open函数文件指针会指向0。

2.4 lseek 函数

lseek 函数用于移动文件描述符指向文件中的位置。

语法

#include #include off_t lseek(int fd, off_t offset, int whence);
  • fd 是文件描述符,通过 open 函数获取。
  • offset 是偏移量,可以是正数、负数或零,用来指定相对于 whence 的偏移量。
  • whence 用于确定 offset 是相对于文件开始位置、当前位置还是文件末尾位置,有三个可选值:
    • SEEK_SET:偏移量相对于文件开头
    • SEEK_CUR:偏移量相对于当前位置
    • SEEK_END:偏移量相对于文件末尾

返回值

  • 如果成功,lseek 函数返回从文件开头到新的文件位置的偏移量。
  • 如果失败,返回值为 -1,并设置全局变量 errno 表示出错的原因。

示例

#include #include #include #include int main() {int fd;off_t offset;fd = open("example.txt", O_RDONLY);if (fd == -1) {perror("open");return 1;}// 设置文件偏移量到文件末尾offset = lseek(fd, 0, SEEK_END);if (offset == -1) {perror("lseek");close(fd);return 1;}printf("File size: %ld bytes\n", offset);close(fd);return 0;}

这些函数是 C 语言中用于文件操作的基础函数,可以通过它们来进行文件的打开、关闭、读写以及定位操作。

下面是一个操作文件的例子

#include #include #include #include #include #include #include int main(){char *buf = "你好啊 世界!"; int fd = open("./file1", O_RDWR); // 尝试以读写模式打开名为 "file1" 的文件if (fd == -1){printf("open file1 failed\n"); // 如果文件打开失败,输出错误消息fd = open("./file1", O_RDWR | O_CREAT, 0600); // 以读写模式和创建标志创建名为 "file1" 的新文件,文件权限为 0600if (fd > 0){printf("create file1 success!\n"); // 如果成功创建文件,输出成功消息}}printf("open success: fd = %d\n", fd); // 打印文件描述符int write_num = write(fd, buf, strlen(buf)); // 向文件写入内容,返回写入的字节数if (write_num != -1){printf("write %d bytes to file\n", write_num); // 打印成功写入的字节数}off_t offset = -21; // 设置偏移量为负数lseek(fd, -21, SEEK_CUR); // 在当前位置偏移 -21 个字节// 读取数据char *temp = (char*)malloc(sizeof(char) * write_num + 1);read(fd,temp,100);printf("%s\n",temp);close(fd); // 关闭文件return 0;}

fopen()fwrite() 是 C 语言标准库 中的文件操作函数。

2.5 fopen和fwrite函数

fopen() 函数

FILE *fopen(const char *path, const char *mode);
  • 作用:用于打开一个文件,并返回一个指向文件的指针。
  • 参数
    • path:字符串,表示要打开的文件的路径和名称。
    • mode:字符串,表示打开文件的模式,例如读取、写入、追加等。常见模式包括 "r"(只读)、"w"(写入)、"a"(追加)、"r+"(读写)、"w+"(读写,创建新文件)、"a+"(读写,追加模式打开)等。

fwrite() 函数

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
  • 作用:用于将数据块写入文件。
  • 参数
    • ptr:要写入的数据的指针。
    • size:每个数据项的字节数。
    • nmemb:要写入的数据项的数量。
    • stream:指向 FILE 结构的指针,即要写入的文件指针。

示例:

#include int main() {FILE *filePointer;char *str = "Hello, this is a test.";size_t written;filePointer = fopen("example.txt", "w"); // 以写入方式打开文件if (filePointer == NULL) {printf("File opening failed.\n");} else {written = fwrite(str, sizeof(char), strlen(str), filePointer); // 写入数据到文件printf("Data written: %zu bytes\n", written);fclose(filePointer); // 关闭文件}return 0;}

这个例子中:

  • 使用 fopen() 打开名为 “example.txt” 的文件,以写入模式。
  • 使用 fwrite() 将字符串 str 的内容写入文件,记录下写入的字节数。
  • 最后使用 fclose() 关闭文件。

fopen()fwrite() 可以结合使用来打开文件并向其写入数据。

2.5 open函数和fopen函数区别

fopen()open() 是用于打开文件的函数,但是它们在使用和功能上有一些区别。

fopen() 函数

  • 属于标准C库(stdio.h)的函数fopen() 函数属于标准C库,提供了一种标准的跨平台的文件操作方式。
  • 返回 FILE* 指针fopen() 返回一个 FILE* 类型的指针,该指针代表了一个文件流,是标准IO库中的概念,不同于系统调用返回的文件描述符。
  • 以文本或二进制模式打开文件fopen() 可以用不同的模式打开文件,例如 “r”(只读模式)、“w”(写入模式)、“a”(追加模式)等。同时也支持二进制模式的操作。
  • 提供了一组标准I/O函数fopen() 之后可以使用诸如 fread()fwrite()fgets()fprintf() 等函数进行文件读写操作。

open() 函数

  • 属于系统调用open() 是系统调用,用于直接操作文件描述符,通常在UNIX系统中使用。
  • 返回文件描述符open() 返回一个文件描述符(整数),代表打开的文件。文件描述符是内核用于标识打开文件的一种方式。
  • 更接近底层文件操作open() 提供了基本的文件打开功能,但不像 fopen() 那样提供高级别的缓冲区管理和格式化读写。
  • 不提供与C库函数相似的接口open() 打开文件后,通常需要使用诸如 read()write()close() 等系统调用来进行文件操作,这些函数与底层系统I/O密切相关。

2.6 主要区别总结

  • fopen() 是C标准库中的函数,提供了更高层次的文件I/O抽象,返回 FILE* 指针,使用标准的C库函数进行文件操作。
  • open() 是系统调用,更接近底层,返回文件描述符,提供了更底层的文件操作,通常用于UNIX和类UNIX系统。

三、综合运用(open函数)

3.1 获取文件长度

通过lseek函数,除了操作定位文件指针,还可以获取到文件大小,注意这里是文件大小,单位是字节。例如在file1文件中事先写入”你好世界!”,那么在gbk编码的情况下,一个中文字符占3个字节,获取到的文件大小就是3*5=15字节。

上述代码如下:

#include #include #include #include #include #include #include int main(){int fd;char *buf = "chenLichen hen shuai!";fd = open("./file1",O_RDWR);int filesize = lseek(fd, 0, SEEK_END);printf("file's size is:%d\n",filesize);close(fd);return 0;}

3.2 追加写入

#include #include #include #include #include #include #include int main(){int fd; // 声明文件描述符变量char *buf = "chenLichen hen shuai!"; // 声明一个字符串指针,并赋值一个字符串常量// 以读写和追加方式打开(如果文件不存在则创建)名为 "file1" 的文件fd = open("./file1", O_RDWR | O_APPEND);// 打印文件打开是否成功的信息和文件描述符printf("open success : fd = %d\n", fd);// 将字符串 buf 中的内容写入到打开的文件中int n_write = write(fd, buf, strlen(buf));if (n_write != -1) {printf("write %d byte to file\n", n_write); // 打印成功写入文件的字节数}close(fd); // 关闭文件描述符对应的文件return 0;}

这段代码的主要操作包括:

  1. 文件打开:

    • 使用 open 函数以读写和追加的方式打开名为 “file1” 的文件,如果文件不存在则创建。
    • O_RDWR 标志表示以读写方式打开文件,O_APPEND 标志表示在文件末尾追加数据。
  2. 写入文件:

    • 将字符串 “chenLichen hen shuai!” 的内容写入到打开的文件中。
    • 使用 write 函数将数据写入文件,并获取成功写入的字节数。
  3. 文件关闭:

    • 使用 close 函数关闭文件描述符,释放相关资源。

这段代码的目的是打开一个文件,将指定的字符串内容追加到文件末尾,并输出写入文件的字节数。

3.3 覆盖写入

以下是代码的注释和解释:

#include #include #include #include #include #include #include int main(){int fd; // 声明文件描述符变量char *buf = "test"; // 声明一个字符串指针,并赋值一个字符串常量// 以读写和截断方式打开(如果文件不存在则创建)名为 "file1" 的文件fd = open("./file1", O_RDWR | O_TRUNC);// 打印文件打开是否成功的信息和文件描述符printf("open success : fd = %d\n", fd);// 将字符串 buf 中的内容写入到打开的文件中int n_write = write(fd, buf, strlen(buf));if (n_write != -1) {printf("write %d byte to file\n", n_write); // 打印成功写入文件的字节数}close(fd); // 关闭文件描述符对应的文件return 0;}

这段代码的主要操作包括:

  1. 文件打开:

    • 使用 open 函数以读写和截断的方式打开名为 “file1” 的文件,如果文件不存在则创建。
    • O_RDWR 标志表示以读写方式打开文件,O_TRUNC 标志表示清空文件内容(截断文件)。
  2. 写入文件:

    • 将字符串 “test” 的内容写入到打开的文件中。
    • 使用 write 函数将数据写入文件,并获取成功写入的字节数。
  3. 文件关闭:

    • 使用 close 函数关闭文件描述符,释放相关资源。

这段代码的目的是打开一个文件,在以读写方式打开文件的同时将文件内容清空,然后将字符串 “test” 写入文件,并输出写入文件的字节数。

3.4 创建文件

以下是代码的注释和解释:

#include #include #include #include #include #include #include int main(){int fd; // 声明文件描述符变量char *buf = "test"; // 声明一个字符串指针,并赋值一个字符串常量// 使用 creat 函数创建一个文件 "/home/CLC/file1",并设置文件权限为用户可读、写和执行fd = creat("/home/CLC/file1", S_IRWXU);return 0;}

这段代码的主要操作包括:

  1. 文件创建:

    • 使用 creat 函数创建一个文件 “/home/CLC/file1”。
    • creat 函数是一个对 open 函数的封装,用于创建文件,如果文件已存在,则将其截断为空文件。
    • S_IRWXU 是文件权限参数,表示用户(拥有者)具有读、写和执行权限。
  2. 文件描述符:

    • creat 函数成功创建文件后,会返回一个文件描述符 fd
    • 在这段代码中并未进行其他文件操作,所以文件描述符没有被使用到其他操作中。

这段代码的目的是使用 creat 函数创建一个名为 “/home/CLC/file1” 的文件,并将文件权限设置为用户可读、写和执行。

3.5 复制文件操作

#include #include #include #include #include #include #include int main(int argc, char **argv){int fdSrc; // 源文件描述符int fdDes; // 目标文件描述符char *readBuf = NULL; // 读取缓冲区指针if (argc != 3){printf("pararm error\n"); // 参数数量错误提示exit(-1);}fdSrc = open(argv[1], O_RDWR); // 以读写方式打开源文件int size = lseek(fdSrc, 0, SEEK_END); // 获取源文件大小lseek(fdSrc, 0, SEEK_SET); // 设置文件指针到文件开头readBuf = (char *)malloc(sizeof(char) * size + 8); // 分配读取缓冲区内存空间int n_read = read(fdSrc, readBuf, size); // 读取源文件内容到缓冲区fdDes = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, 0600); // 以读写方式创建目标文件,若存在则清空内容int n_write = write(fdDes, readBuf, strlen(readBuf)); // 将读取缓冲区内容写入目标文件close(fdSrc); // 关闭源文件描述符close(fdDes); // 关闭目标文件描述符return 0;}

上述这段代码是一个简单的文件复制程序,它通过命令行参数接收两个文件名,将第一个文件的内容复制到第二个文件中。

3.6 查找文件中的字符串,并修改

#include #include #include #include #include #include #include int main(int argc, char **argv) {int fdSrc; // 源文件的文件描述符char *readBuf = NULL; // 用于读取文件内容的缓冲区if (argc != 2) {printf("参数错误\n");exit(-1);}// 以读写方式打开命令行参数指定的文件fdSrc = open(argv[1], O_RDWR);// 获取文件大小int size = lseek(fdSrc, 0, SEEK_END);lseek(fdSrc, 0, SEEK_SET);// 分配内存给 readBuf,用于存储文件内容readBuf = (char *)malloc(sizeof(char) * size + 8);// 将文件内容读取到 readBuf 中int n_read = read(fdSrc, readBuf, size);// 在读取缓冲区中查找子字符串char *p = strstr(readBuf, "world");if (p == NULL) {printf("未找到\n");exit(-1);}p = p + strlen("world");*p = '!'; // 修改 "LENG=" 后面的字符为 '5'// strncpy(p + 1, "body", 6);// 将文件指针移到文件开头lseek(fdSrc, 0, SEEK_SET);// 将修改后的内容写回文件int n_write = write(fdSrc, readBuf, strlen(readBuf));// 关闭文件描述符close(fdSrc);// 释放动态分配的内存free(readBuf);return 0;}

四、综合运用(fopen函数)

4.1 读取文件

#include #include int main(){// 定义文件指针变量FILE *fp;// 定义一个字符串指针并赋值char *str = "你好";// 定义一个用于存储读取内容的缓冲区char readBuf[128] = {0};// 以读写方式打开一个名为 "chen.txt" 的文件fp = fopen("./chen.txt", "w+");// 将字符串 str 写入文件中fwrite(str, sizeof(char), strlen(str), fp);// 将文件指针移到文件开头fseek(fp, 0, SEEK_SET);// 从文件中读取数据到 readBuf 缓冲区中fread(readBuf, sizeof(char), strlen(str), fp);// 输出从文件读取的数据printf("read data: %s\n", readBuf);// 关闭文件fclose(fp);return 0;}

参考文章

推荐文章:Linux 文件基本属性