目录
示例代码一:以只读方式打开test.txt文件,文件不存在则报错
示例代码二:以只写方式打开文件test.txt, 文件不存在则创建,文件存在则清空
示例代码三:验证一个进程(现在可以理解成一个程序)能打开的最大文件数量
示例代码一:以只写模式打开文件,如果不存在则创建,如果存在则清空内容
一、前言(必看)
文件访问方式对比
(1)标准IO与文件IO的区别
-
标准IO:通过
FILE
流指针访问文件。 -
文件IO:通过文件描述符访问文件。
(2)文件描述符
-
定义:文件描述符是一个非负整数,作为文件的唯一标识符,类似于学号。
-
分配规则:从0开始,顺序分配。
-
获取方式:当打开或创建文件时,内核会向进程返回一个文件描述符。
(3)进程运行时的默认文件描述符
进程运行时,会自动打开三个文件,分别对应标准输入、标准输出和标准错误输出:
文件类型 | 标准IO(流) | 文件IO(文件描述符) |
---|---|---|
标准输入 | stdin | 0 |
标准输出 | stdout | 1 |
标准错误输出 | stderr | 2 |
(4)总结
-
标准IO使用
FILE
流指针,文件IO使用文件描述符。 -
文件描述符从0开始顺序分配,是文件的唯一标识符。
-
进程默认打开的三个文件分别对应文件描述符0、1、2,分别表示标准输入、标准输出和标准错误输出。
二、系统调用接口
2.1 打开文件:open函数
作用
open
函数用于打开或创建一个文件,并返回文件描述符,以便后续的读写操作。头文件
#include <fcntl.h> #include <sys/types.h> #include <sys/stat.h>函数原型
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_TRUNC: 当文件存在时,清空文件内容
O_APPEND: 当文件存在时,追加到文件末尾
mode
: 当使用O_CREAT
标志时,指定新文件的权限模式。通常使用八进制数表示,如0644
。如果用符号表示,
0664
对应的权限为:-rw-rw-r-- (Linux基础)文件所有者:
rw-
(读写)所属组:
rw-
(读写)其他用户:
r--
(只读)返回值
成功: 返回文件描述符(一个非负整数)。
失败: 返回
-1
,并设置errno
以指示错误类型。
示例代码一:以只读方式打开test.txt文件,文件不存在则报错
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h> // 包含 close() 函数的头文件
int main(int argc, char *argv[])
{
// 1. 以只读方式打开 test.txt 文件
int fp = open("test.txt", O_RDONLY); // O_RDONLY 是只读模式
// 2. 判断是否打开成功
if (fp < 0) {
// 打开失败
perror("open"); // 打印错误信息
return -1; // 返回错误码
}
// 3. 打开成功,打印文件描述符编号
printf("fp = %d\n", fp); // 打印文件描述符编号
// 4. 关闭文件描述符
close(fp); // 关闭文件描述符,释放资源
return 0; // 程序正常结束
}
这里文件描述符 fp = 3的原因是因为前面已经说过,程序运行时,会默认打开三个文件描述符,分别是0,1,2,对应输入、输出、错误,而文件描述符是顺序分配的,所以这里的文件描述符是 3,再创建一个就是 4(没有关闭任何一个文件描述符的前提下)
示例代码二:以只写方式打开文件test.txt, 文件不存在则创建,文件存在则清空
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h> // 包含 close() 函数的头文件
int main() {
// 1. 以只写方式打开文件,如果文件不存在则创建,如果存在则清空内容
int fp = open("test1.txt", O_WRONLY | O_CREAT | O_TRUNC, 0664);
// 2. 判断是否打开成功
if (fp < 0) {
perror("open"); // 打印错误信息
return -1; // 返回错误码
}
// 3. 打开成功,打印文件描述符
printf("fp = %d\n", fp);
// 4. 关闭文件
close(fp);
return 0; // 程序正常结束
}
特别注意:当使用 O_CREAT
标志时,open函数的第三个参数就需要填写上了,指定创建文件的权限,一般为0664,| 符号表示,三个都要 ,与的意思。
示例代码三:验证一个进程(现在可以理解成一个程序)能打开的最大文件数量
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main() {
int file_nums = 3; // 初始文件数量(默认打开的三个文件:0, 1, 2)
int fp; // 文件描述符
// 1. 不断尝试打开文件
while (1) {
fp = open("test.txt", O_RDONLY); // 以只读方式打开文件
if (fp < 0) {
// 打开失败
perror("open"); // 打印错误信息
break; // 退出循环
}
// 2. 打开成功
file_nums++; // 增加打开的文件数量
}
// 3. 打印当前打开的文件数量
printf("file nums = %d\n", file_nums);
return 0;
}
得出结论::一个进程最多同时打开1024个文件
2.2 读取文件:read函数
作用
read
函数用于从文件描述符对应的文件中读取数据。头文件
#include <unistd.h>函数原型
ssize_t read(int fd, void *buf, size_t count);参数
fd
: 文件描述符,通常由open
函数返回。
buf
: 用于存储读取数据的缓冲区地址。
count
: 要读取的字节数。返回值
成功: 返回实际读取的字节数。如果返回
0
,表示已到达文件末尾(EOF)。失败: 返回
-1
,并设置errno
以指示错误类型。
示例代码一:读取test.txt 文件内容,并打印到屏幕上
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{
// 检查命令行参数
if (argc < 2) {
fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
return -1;
}
// 1. 打开文件
int fp = open(argv[1], O_RDONLY); // 以只读方式打开文件
if (fp < 0) {
perror("open"); // 打印错误信息
return -1;
}
// 2. 读取文件所有内容并显示到屏幕上
char buf[100];
while (1) {
// 每次读之前先清空 buf,防止遗留数据
memset(buf, 0, sizeof(buf)); // 全部用 \0 填充
int ret = read(fp, buf, sizeof(buf) - 1); // 读取数据
if (ret < 0) {
// 读取失败
perror("read");
break;
}
else if (ret == 0)
{
// 读取到文件末尾了,文件为空也会这样
printf("read file end\n");
break;
}
// 打印读取的内容
printf("%s", buf);
}
// 3. 关闭文件
close(fp);
return 0;
}
为什么是 sizeof(buf)-1 : 因为字符串是以 \0 结尾,代码中定义的缓冲区 buf
的大小为 100 字节。如果使用 sizeof(buf)
(即 100)作为 read
的读取长度,read
可能会将缓冲区完全填满,没有空间放置 \0
。因此,通过 sizeof(buf) - 1
,确保最多只读取 99 个字节,留出最后一个字节用于存储 \0(会自动添加)
。
示例代码二:读取文件的行数
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
// 检查命令行参数
if (argc < 2) {
fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
return -1;
}
// 1. 打开文件
int fp = open(argv[1], O_RDONLY); // 以只读模式打开文件
if (fp < 0) {
perror("open"); // 打印错误信息
return -1;
}
// 2. 逐字符读取文件内容并统计行数
char ch;
int ret;
int line_count = 0; // 行数计数器
int empty = 1; // 标记文件是否为空(1 表示为空)
while ((ret = read(fp, &ch, 1)) > 0)
{
empty = 0; // 文件不为空
if (ch == '\n') { // 如果遇到换行符,行数加 1
line_count++;
}
}
// 3. 处理文件末尾可能缺少换行符的情况
if (empty) {
printf("文件为空\n"); // 文件为空
} else if (ch != '\n') {
line_count++; // 文件末尾没有换行符,但有内容
}
// 4. 关闭文件
close(fp);
// 5. 输出结果
printf("文件的行数: %d\n", line_count);
return 0;
}
代码稍微复杂一点点,如果看不懂,评论区告诉我
标签:文件,return,函数,int,C语言,IO,搞懂,include,buf From: https://blog.csdn.net/weixin_67914777/article/details/144833845