一、文件IO
文件IO是Linux内核提供的文件操作接口,属于系统调用。 核心接口:open()、read()、write()、close()。
1. open 打开文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
功能:打开一个文件,获取文件描述符。
参数说明
pathname:待打开文件路径名称flags:打开方式标志位,可以多标志位按位或组合
| flags | 含义 |
|---|---|
| O_RDONLY | 只读 |
| O_WRONLY | 只写 |
| O_RDWR | 读写 |
| O_CREAT | 文件不存在则创建 |
| O_TRUNC | 打开时清空文件内容 |
| O_APPEND | 追加模式,写在文件末尾 |
标准IO mode 和 文件IO flags对应关系
| 标准IO mode | 文件IO flags |
|---|---|
| "r" | O_RDONLY |
| "r+" | O_RDWR |
| "w" | O_WRONLY | O_TRUNC | O_CREAT,0664 |
| "w+" | O_RDWR | O_TRUNC | O_CREAT,0664 |
| "a" | O_WRONLY | O_CREAT | O_APPEND,0664 |
| "a+" | O_RDWR | O_CREAT | O_APPEND,0664 |
mode:新建文件权限,实际权限 =mode & ~umask;普通文件常用0664,满权限0777。
返回值:成功返回文件描述符,失败返回-1。
文件描述符 打开文件后内核分配的非负小整数;范围默认
0‑1023,共1024个;分配规则:取当前最小未被使用的编号。 系统默认已经打开:
标准IO 文件IO文件描述符宏 stdin 0(STDIN_FILENO) stdout 1(STDOUT_FILENO) stderr 2(STDERR_FILENO)
2. close 关闭文件
#include <unistd.h>
int close(int fd);
参数:fd为文件描述符。 返回:成功0,失败‑1。
注意:打开后必须关闭,否则发生文件描述符泄漏。
3. write 写数据
ssize_t write(int fd, const void *buf, size_t count);
fd:文件描述符buf:待写入数据缓冲区首地址count:期望写入字节数 返回:成功返回实际写入字节数;失败返回‑1。
4. read 读数据
ssize_t read(int fd, void *buf, size_t count);
fd:文件描述符buf:存放读取数据的缓冲区count:期望读取字节数 返回:成功返回实际读到字节数;读到文件末尾返回0;失败返回‑1。
5. read + write 实现文件拷贝
int file_copy(const char *srcfile, const char *dstfile)
{
int fdsrc = open(srcfile, O_RDONLY);
int fddst = open(dstfile, O_WRONLY | O_CREAT | O_TRUNC, 0664);
if (-1 == fdsrc || -1 == fddst)
{
printf("open error\n");
return -1;
}
char buff[1024] = {0};
ssize_t size = 0;
while ((size = read(fdsrc, buff, sizeof(buff))) > 0)
{
write(fddst, buff, size);
}
close(fdsrc);
close(fddst);
return 0;
}
6. lseek 文件定位
off_t lseek(int fd, off_t offset, int whence);
offset:偏移字节数whence偏移基准:SEEK_SET:文件开头SEEK_CUR:当前读写位置SEEK_END:文件末尾 返回:成功返回当前距离文件开头偏移量;失败返回‑1。
二、文件IO和标准IO的区别
| 对比项 | 标准IO | 文件IO |
|---|---|---|
| 操作对象 | FILE *(文件流指针) | fd(文件描述符int) |
| 函数来源 | C库函数,可移植性强 | Linux系统调用,可移植弱 |
| 缓冲区 | 用户层带缓冲区,减少系统调用,效率高 | 无用户层缓冲区,实时性好 |
| 适用场景 | 普通文件读写 | 普通文件、硬件设备文件 |
缓冲区分类
- 行缓冲:终端交互,默认1024字节;
\n、程序结束、fflush、缓冲区满触发刷新。 - 全缓冲:普通文件,默认4096字节;关闭文件、程序结束、缓冲区满、fflush触发刷新。
- 无缓冲:stderr标准错误输出,直接输出。
三、目录IO
目录操作API:opendir、readdir、closedir、mkdir。
1. opendir 打开目录
DIR *opendir(const char *name);
参数:目录名;返回目录流指针;失败返回NULL。
2. closedir 关闭目录
int closedir(DIR *dirp);
返回成功0,失败‑1。
3. readdir 读取目录项
struct dirent *readdir(DIR *dirp);
返回struct dirent*,读到目录末尾/出错返回NULL。
struct dirent {
ino_t d_ino; /* inode编号 */
off_t d_off;
unsigned short d_reclen;
unsigned char d_type;/* 文件类型 */
char d_name[256]; /* 文件名 */
};
4. mkdir 创建目录
int mkdir(const char *pathname, mode_t mode);
参数:目录名,目录权限;成功返回0,失败‑1。
创建文件对比:
mkdir:创建文件夹touch命令:创建普通文件open()/fopen():代码内创建普通文件
目录遍历示例代码
遍历/dev目录,过滤隐藏文件,打印文件名与inode号
int main(void)
{
DIR *pdir = opendir("/dev");
if (NULL == pdir)
{
printf("opendir error\n");
return -1;
}
while (1)
{
struct dirent *pinfo = readdir(pdir);
if (NULL == pinfo)
{
break;
}
if ('.' == pinfo->d_name[0])
{
continue;
}
printf(" %s : %ld\n", pinfo->d_name, pinfo->d_ino);
}
closedir(pdir);
return 0;
}
四、其他常用接口
1. 格式化输出系列
int printf(const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
int dprintf(int fd, const char *format, ...);
int sprintf(char *str, const char *format, ...);
printf:输出到标准输出stdoutfprintf:格式化输出到文件流FILE*dprintf:格式化输出到文件描述符fdsprintf:格式化输出到内存字符数组,常用于数字转字符串、字符串拼接
2. strtok 字符串分割
char *strtok(char *str, const char *delim);
功能:按分隔符delim切割字符串;第一次传入原字符串,后续调用传NULL;返回分割得到子串首地址;分割完毕返回NULL。
⚠会修改原字符串。
3. 出错处理函数
char *strerror(int errnum);
void perror(const char *s);
strerror:将错误码errno转为错误信息字符串。perror:打印自定义提示字符串 + 系统错误原因。