提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
文件输入输出(File Input/Output,简称文件I/O)是编程中一个基本且重要的概念。它涉及到在程序和存储设备(如硬盘、闪存驱动器等)之间读取或写入数据的过程。在不同的编程语言中,文件I/O的实现方式会有所不同,但基本原理相似。本文以C语言为主
一、文件IO是什么?
文件IO就是在POSIX(可移植操作系统接口)中定义的一组输入输出的函数。涉及操作系统和应用程序之间的交互,用于读取和写入存储在永久性存储介质(如硬盘、SSD、USB闪存盘等)上的数据。
特点:
- 没有缓存机制
- 围绕文件描述符进行操作,相当于标准IO中的流(FILE*),文件描述符是正整数。
- 默认打开三个描述符
- 标准输入
0
- 标准输出
1
- 标准错误
2
- 标准输入
- 除目录文件,其他类型文件都可以操作
二、函数
1.打开文件
需要引用三个头文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname,int flags,...)
功能:
打开文件
参数:
pathname:文件路径名
flags:文件打开方式
...:第三个参数在打开方式为创建时,用来设置文件权限。后面会细说
返回值:
成功:文件描述符
失败:-1
打开方式有以下几种
- O_RDONLY 只读
- O_WRONLY 只写
- O_RDWR 读写
- O_CREAT 创建
- O_TRUNC 清空
- O_APPEND 追加
在程序中可以看到这是一组宏定义
也可以以组合的方式,实现类似标准IO打开文件的功能
文件IO | 标准IO | 功能 |
---|---|---|
O_RDONLY | r | 只读 |
O_RDWR | r+ | 读写 |
O_WRONLY|O_TRUNC|O_CREAT | w | 写,打开始会覆盖原文,没有对应文件则创建文件 |
O_RDWR|O_TRUNC|O_CREAT | w+ | 读写,打开始会覆盖原文,没有对应文件则创建文件 |
O_APPEND|O_CREAT|O_WRONLY | a | 从文档末尾开始写入,没有对应文件则创建文件 |
O_RDWR|O_APPEND|O_CREAT | a+ | 从文档末尾开始读写,没有对应文件则创建文件 |
第三个参数
设置文件权限,在创建文件时才需要添加
如
//创建一个test文件,文件权限为666,0开头表示八进制数
open("./test",O_CREATE|O_REWR,0666);
这里我们将文件权限值设为了666(所有人可读写),但实际的情况是664,因为这个函数会自动将我们的权限值与上一个~umask
umask的值为 0002
实际情况为:
0666&(~umask)
需要按二进制运算
110 110 110 &(~(000 000 010))
110 110 110
&111 111 101
=110 110 100
=>664
所有在这个函数中无论我们怎样设置权限,其他分组的用户都无法获得写的权限,
关闭文件
int close(int fd);
功能:
关闭文件
参数:
文件描述符
文件读写操作
头文件为#include <unistd.h>
读操作
ssize_t read(int fd, void *buf, size_t count);
功能:
从一个已打开的可读文件中读取数据
参数:
fd 文件描述符
buf 存放位置
count 期望的个数
返回值:
成功:
实际读到的个数
失败:
返回-1:表示出错,并设置errno号
返回0:表示读到文件结尾
写操作
ssize_t write(int fd, const void *buf, size_t count);
功能:
向指定文件描述符中,写入 count个字节的数据。
参数:
fd 文件描述符
buf 要写的内容
count 期望值
返回值:
成功:实际写入数据的个数
失败 : -1
例子
//已有文件test1,里面有一段文本,我们将他读取出来,再写入新的文本
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
int fp;
char buf1[32] = "";
char buf2[32] = "Is a rookie\n";
// 以读写方式打开文件,返回文件描述符号
fp = open("./test1",O_RDWR);
//期望读取32个
size_t num = read(fp,buf1,32);
printf("实际读取个数%ld\n读取内容:%s",num,buf1);
// 期望写入32个
num = write(fp,buf2,32);
printf("实际写入个数%ld\n写入内容:%s",num,buf2);
}
运行结果
我们的字符串数组buf2
的实际内容长度明显不足32,但程序程序还是按照我们的要求写入了32个字符,那多出来的那一部分是什么
再让我们看看目标文档
通过以上结果我们可以看到
- 读取的期望值是我们一次所能读取到的最大值,当目标文本内容不足时,会按实际长度读取
- 写入时的期望值就是要写的个数,当目标数据不足时,会添加一些我们看不懂的东西
2.文件定位操作
每次对文件进行读取或写入操作时,文件光标都会向后移动对应的长度。如果想让光标移动到指定位置进行读写操作,需要使用定位函数
off_t lseek(int fd, off_t offset, int whence);
功能:
设定文件的光标位置
参数:
fd:文件描述符
offset:偏移量
正数:向文件结尾位置移动
负数:向文件开始位置
whence 相对位置
SEEK_SET 开始位置
SEEK_CUR 当前位置
SEEK_END 结尾位置
返回值:成功:文件的当前位置
总结
文件IO的操作与标准IO类似,可以对比理解。