今日学习内容
1. 文件IO与标准IO核心对比
特性 | 标准IO | 文件IO |
---|---|---|
实现层 | C标准库 | Linux内核系统调用 |
缓冲机制 | 全缓冲/行缓冲 | 无缓冲(实时读写) |
操作对象 | FILE* 流指针 | 整型文件描述符(fd) |
移植性 | 跨平台兼容 | Linux特有 |
典型应用场景 | 普通文件操作 | 硬件设备/特殊文件操作 |
性能特点 | 减少系统调用(批量操作高效) | 实时响应(适合高频小数据) |
2. 文件描述符(File Descriptor)
(1) 内核级文件访问句柄
- 本质:整数标识符(索引内核文件表)
- 预定义fd:
fd 符号 设备 0 STDIN
标准输入 1 STDOUT
标准输出 2 STDERR
标准错误
(2) 生命周期管理
int fd = open("file.txt", O_RDWR); // 获取fd
read(fd, buf, size); // 使用fd操作
close(fd); // 释放fd(必须!)
3. 文件权限控制:umask机制
(1) 权限计算规则
权限计算遵循公式:mode & ~umask
- 查看umask:终端输入
umask
4. 核心系统调用详解
(1) 文件打开:open
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
int open(const char *pathname, int flags, mode_t mode);
参数 | 说明 |
---|---|
pathname | 文件路径 |
flags | 打开标志 |
mode | 创建文件时的权限(仅O_CREAT时有效) |
常用flags组合:
场景 | flags组合 |
---|---|
只读打开 | O_RDONLY |
只写打开 | O_WRONLY |
读写打开 | O_RDWR |
创建文件 | O_CREAT |
追加写入 | O_APPEND |
清空文件 | O_TRUNC |
(2) 数据读取:read
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
- 返回值:
- 成功:实际读取字节数
- 文件末尾:0
- 错误:-1
(3) 数据写入:write
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
- 返回值:实际写入字节数(可能小于请求值)
(4) 文件定位:lseek
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
whence | 定位基准 |
---|---|
SEEK_SET | 文件开头 |
SEEK_CUR | 当前位置 |
SEEK_END | 文件末尾 |
典型应用:
lseek(fd, 0, SEEK_END); // 定位到文件末尾
(5) 文件关闭:close
#include <unistd.h>int close(int fd); // 成功返回0,失败返回-1
打开的文件描述符必须显式关闭!
5. 代码
open.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc, char const *argv[])
{int fd = open("./2.txt", O_WRONLY | O_CREAT | O_TRUNC, 0664);if(-1 == fd){printf("error\n");return -1;}printf("fd = %d\n", fd);close(fd);return 0;
}
write.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc, char const *argv[])
{int fd = open("./2.txt", O_WRONLY | O_CREAT | O_TRUNC, 0664);if(-1 == fd){printf("error\n");return -1;}char *buf = "hello";write(1, buf, sizeof(buf));close(fd);return 0;
}
read.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc, char const *argv[])
{int fd = open("./2.txt", O_RDONLY);if(-1 == fd){printf("error\n");return -1;}char buff[1024] = {0};ssize_t cnt = read(fd, buff, sizeof(buff));// printf("cnt = %ld\n", cnt);printf("buff = %s\n", buff);close(fd);return 0;
}
cats
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc, char const *argv[])
{int fd = open(argv[1], O_RDONLY);if(-1 == fd){printf("error\n");return -1;}char buff[1024] = {0};while(1){ssize_t cnt = read(fd, buff, sizeof(buff));write(1, buff, cnt);if(0 == cnt){break;}}close(fd);return 0;
}
copy.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc, char const *argv[])
{int fd = open(argv[1], O_RDONLY);if(-1 == fd){printf("error\n");return -1;}char buff[1024] = {0};while(1){ssize_t cnt = read(fd, buff, sizeof(buff));write(1, buff, cnt);if(0 == cnt){break;}}close(fd);return 0;
}
lseek.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc, char const *argv[])
{int fd = open("./1.txt", O_RDONLY);if(fd < 0){printf("error\n");return -1;}off_t len = lseek(fd, 0, SEEK_END);printf("%ld\n", len);lseek(fd, 0, SEEK_SET);close(fd);return 0;
}
rizhi.c
#include <stdio.h>
#include <time.h>
#include <unistd.h>
FILE *fp = NULL;
int init_log()
{fp = fopen("./log.txt", "a");if(NULL == fp){printf("open error\n");return -1;} return 0;
}int write_log(int level)
{time_t now = time(NULL);struct tm *pt = localtime(&now);const char *plevel = {0};switch (level) {case 2: plevel = "ERROR"; break;case 1: plevel = "WARNING"; break;case 0: plevel = "INFO"; break;}fprintf(fp, "[%d-%d-%d %d:%d:%d] [%d]:%s\n", pt->tm_year+1900, pt->tm_mon+1,pt->tm_mday,pt->tm_hour, pt->tm_min, pt->tm_sec, level, plevel);return 0;
}void unint_log()
{fclose(fp);
}int main(void)
{init_log();int i;for(i = 0; i < 100; ++i){write_log(2); write_log(0);write_log(1); }unint_log();return 0;
}
总结
- 文件IO核心价值:
- 直接内核交互 → 实时性保障
- 设备文件操作唯一途径
- 系统调用:
操作 关键注意 open 正确处理O_CREAT的mode参数 read/write 循环处理部分写入/读取 lseek 支持负偏移(向前回溯) close 配对调用防止fd泄漏 - 嵌入式场景适配:
- 设备驱动开发必用文件IO
- 日志系统优先选无缓冲写入(防断电丢失)
- 敏感文件设置严格权限(
open(..., 0600)
)