目录
一、C 标准库文件操作
1. 文件的写入
2. 文件的读取
3. 数据输出到显示器
4. 标准输入输出流
二、C 标准库文件操作模式
三、系统调用文件操作
1. 文件的打开与描述符
2. 文件的读取
3. 文件操作标志
4. 文件权限
5. 文件描述符
四、C 标准库与系统调用的比较
1. 功能对比
2. 底层交互
3. 使用场景
一、C 标准库文件操作
1. 文件的写入
以下是一个使用 C 标准库函数 fwrite
写入文件的示例:
#include <stdio.h>
#include <string.h>int main()
{FILE *fp = fopen("myfile", "w"); // 以写模式打开文件if (!fp) {printf("fopen error!\n");return 1;}const char *msg = "hello bit!\n";int count = 5;while (count--) {fwrite(msg, strlen(msg), 1, fp); // 将字符串写入文件}fclose(fp); // 关闭文件return 0;
}
-
fopen
函数用于打开或创建文件。"w"
模式表示以写模式打开文件,如果文件不存在则创建一个新文件,如果文件存在则清空其内容。 -
fwrite
函数将指定内存区域的内容写入文件。第一个参数是内存区域的指针,第二个参数是每个元素的大小,第三个参数是元素的数量,第四个参数是文件指针。 -
fclose
函数用于关闭文件,释放与文件相关的资源。
2. 文件的读取
以下是一个使用 C 标准库函数 fread
读取文件的示例:
#include <stdio.h>
#include <string.h>int main()
{FILE *fp = fopen("myfile", "r"); // 以读模式打开文件if (!fp) {printf("fopen error!\n");return 1;}char buf[1024];const char *msg = "hello bit!\n";while (1) {ssize_t s = fread(buf, 1, strlen(msg), fp); // 从文件中读取数据到缓冲区if (s > 0) {buf[s] = 0; // 将缓冲区内容转换为字符串printf("%s", buf);}if (feof(fp)) { // 检查是否到达文件末尾break;}}fclose(fp);return 0;
}
-
fopen
函数以读模式打开文件。 -
fread
函数从文件中读取数据到指定的缓冲区。第一个参数是缓冲区的指针,第二个参数是每个元素的大小,第三个参数是元素的数量,第四个参数是文件指针。 -
feof
函数用于检查文件是否已到达末尾。
3. 数据输出到显示器
以下是一个使用多种方法将数据输出到显示器的示例:
#include <stdio.h>
#include <string.h>int main()
{const char *msg = "hello fwrite\n";fwrite(msg, strlen(msg), 1, stdout); // 使用 fwrite 输出到标准输出printf("hello printf\n"); // 使用 printf 输出fprintf(stdout, "hello fprintf\n"); // 使用 fprintf 输出return 0;
}
-
stdout
是标准输出流,指向显示器。 -
fwrite
、printf
和fprintf
都可以将数据输出到标准输出流。
4. 标准输入输出流
C 语言默认提供三个标准输入输出流:
-
stdin
:标准输入流,默认为键盘输入。 -
stdout
:标准输出流,默认为显示器输出。 -
stderr
:标准错误流,默认为显示器输出。
以下是一个示例:
#include <stdio.h>
#include <string.h>int main()
{char buf[1024];ssize_t s = read(0, buf, sizeof(buf)); // 从标准输入(文件描述符0)读取if (s > 0) {buf[s] = 0;write(1, buf, strlen(buf)); // 写入到标准输出(文件描述符1)write(2, buf, strlen(buf)); // 写入到标准错误(文件描述符2)}return 0;
}
-
文件描述符
0
对应stdin
。 -
文件描述符
1
对应stdout
。 -
文件描述符
2
对应stderr
。
二、C 标准库文件操作模式
C 标准库的 fopen
函数支持多种文件操作模式,以下是一些常见的模式:
模式 | 描述 |
---|---|
r | 打开纯文本文件以只读方式,文件不能不存在。 |
r+ | 打开纯文本文件用于读/写,文件不能不存在。 |
w | 打开纯文本文件用于写覆盖,若文件存在则清空,不存在则创建。 |
w+ | 打开纯文本文件用于读/写覆盖,若文件存在则清空,不存在则创建。 |
a | 打开纯文本文件用于在文件尾部追加写入。 |
a+ | 打开纯文本文件用于读/写,并在尾部追加新数据。 |
以下是一个使用 a+
模式的示例:
#include <stdio.h>int main()
{FILE *fp = fopen("myfile", "a+"); // 追加写入模式if (!fp) {printf("fopen error!\n");return 1;}const char *msg = "add new line\n";fwrite(msg, strlen(msg), 1, fp);fclose(fp);return 0;
}
-
a+
模式表示以读写方式打开文件,并在文件尾部追加新数据。
三、系统调用文件操作
1. 文件的打开与描述符
以下是一个使用系统调用 open
打开文件的示例:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>int main()
{umask(0); // 设置文件权限掩码int fd = open("myfile", O_WRONLY | O_CREAT, 0644); // 打开或创建文件if (fd < 0) {perror("open");return 1;}const char *msg = "hello bit!\n";int len = strlen(msg);write(fd, msg, len); // 写入数据到文件close(fd); // 关闭文件return 0;
}
-
open
函数用于打开或创建文件。第二个参数是标志位,第三个参数是文件权限。 -
O_WRONLY | O_CREAT
表示以只写方式打开文件,如果文件不存在则创建。 -
0644
是文件权限,表示文件所有者具有读写权限,组用户和其他用户具有只读权限。 -
write
函数将数据写入文件。第一个参数是文件描述符,第二个参数是数据的指针,第三个参数是数据的长度。 -
close
函数用于关闭文件描述符。
2. 文件的读取
以下是一个使用系统调用 read
读取文件的示例:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>int main()
{int fd = open("myfile", O_RDONLY); // 以只读模式打开文件if (fd < 0) {perror("open");return 1;}const char *msg = "hello bit!\n";char buf[1024];ssize_t s = read(fd, buf, strlen(msg)); // 读取文件数据if (s > 0) {printf("%s", buf);}close(fd);return 0;
}
-
read
函数从文件描述符中读取数据。第一个参数是文件描述符,第二个参数是数据的缓冲区,第三个参数是最大读取长度。 -
返回值
s
表示实际读取的字节数。
3. 文件操作标志
系统调用 open
的第二个参数是标志位,以下是一些常见的标志位:
标志位 | 描述 |
---|---|
O_RDONLY | 以只读方式打开文件。 |
O_WRONLY | 以只写方式打开文件。 |
O_RDWR | 以读写方式打开文件。 |
O_CREAT | 如果文件不存在则创建。 |
O_APPEND | 以追加模式写入。 |
O_TRUNC | 如果文件存在,则清空文件内容。 |
O_EXCL | 如果使用 O_CREAT 标志时文件已存在,则失败。 |
4. 文件权限
系统调用 open
的第三个参数是文件权限,使用八进制表示。以下是一些常见的权限位:
权限位 | 描述 |
---|---|
0400 | 所有者具有读权限。 |
0200 | 所有者具有写权限。 |
0100 | 所有者具有执行权限。 |
0040 | 组用户具有读权限。 |
0020 | 组用户具有写权限。 |
0010 | 组用户具有执行权限。 |
0004 | 其他用户具有读权限。 |
0002 | 其他用户具有写权限。 |
0001 | 其他用户具有执行权限。 |
5. 文件描述符
-
文件描述符是一个小整数,由操作系统分配。
-
程序默认拥有三个文件描述符:
-
0
:标准输入(stdin
)。 -
1
:标准输出(stdout
)。 -
2
:标准错误(stderr
)。
-
以下是一个使用文件描述符输出数据的示例:
#include <unistd.h>
#include <string.h>int main()
{char buf[] = "Hello World!\n";write(1, buf, strlen(buf)); // 使用文件描述符1(stdout)输出return 0;
}
-
write(1, buf, strlen(buf))
表示将数据写入到标准输出流。
文件描述符就是从0开始的小整数。当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件。于是就有了file结构体。表示一个已经打开的文件对象。而进程执行open系统调用,所以必须让进程和文件关联起来。每个进程都有一个指针*files, 指向一张表files_struct,该表最重要的部分就是包涵一个指针数组,每个元素都是一个指向打开文件的指针。本质上,文件描述符就是该数组的下标。所以,只要拿着文件描述符,就可以找到对应的文件 。
四、C 标准库与系统调用的比较
1. 功能对比
功能 | C 标准库 | 系统调用 |
---|---|---|
文件打开 | fopen | open |
文件读取 | fread | read |
文件写入 | fwrite | write |
文件关闭 | fclose | close |
文件定位 | fseek | lseek |
标准输入输出 | stdin, stdout, stderr | 文件描述符0、1、2 |
2. 底层交互
-
C 标准库函数是封装好的函数,内部调用了系统调用。
-
例如,
fopen
是基于open
实现的。 -
fwrite
是基于write
实现的。
-
-
系统调用直接与操作系统内核交互,执行效率更高,但使用更复杂。
3. 使用场景
-
C 标准库:
-
适合快速开发和处理简单的文件操作。
-
提供了缓冲机制,数据处理更高效。
-
-
系统调用:
-
适合对底层控制要求较高的场景,如设备驱动程序、高性能文件处理等。
-
对文件描述符的直接操作,灵活性更高。
-