一个通用的 IO 模型通常包括打开文件、读写文件、关闭文件这些基本操作, 主要涉及到 4 个函数: open()、 read()、 write()以及 close()。下面是一个具体的读写应用的例子:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc,char *argv[])
{
char buffer[1024]; //定义缓冲区
int fd1,fd2; //用于保存文件描述符
int ret;
/*打开src_file文件*/
fd1 = open("./src_file",O_RDONLY); //以只读的方式打开当前目录下的src_file文件
if(fd1 == -1){ //文件描述符为-1,表示打开失败
printf("Open file:src_file Failed!\r\n");
return -1;
}
/*新建test_file文件并打开*/
fd2 = open("./test_file",O_WRONLY | O_CREAT | O_EXCL,S_IRWXU | S_IRGRP | S_IROTH);
//O_WRONLY以读写的方式打开
//O_CREAT如果文件不存在则创建该文件
//O_EXCL 如果文件已存在则返回错误
//S_IRWXU 允许文件所属者读、写、执行文件
//S_IRGRP 允许同组用户读文件
//S_IROTH 允许其他用户读文件
if(fd2 == -1){
printf("Open file:test_file Failed!\r\n");
ret = -1;
goto err1;
}
/*将src_file文件的读写位置便宜到500个字节处*/
ret = lseek(fd1, 500, SEEK_SET);
if(ret == -1){
goto err2;
}
/* 读取 src_file 文件数据,大小 1KByte */
ret = read(fd1, buffer, sizeof(buffer));
if (ret == -1) {
printf("Read file:test_file Failed!\r\n");
goto err2;
}
/*将buffer中的数据写入到test_file文件中,大小为1Kb*/
ret = write(fd2, buffer, sizeof(buffer));
if(ret == -1){
printf("Write file:test_file Failed!\r\n");
goto err2;
}
printf("Test:Successful\r\n");
return 0;
err2:
close(fd2);
err1:
close(fd1);
return ret;
}
这个读写应用实现的功能如下:
①打开src_file文件
②新建test_file文件并打开
③将文件src_file的读写位置设置到500
④从sec_file文件中读1Kb的数据到缓冲buffer中
⑤将buffer中的数据写入test_file文件中
从这个简单的应用中学习一下文件I/O的基础部分
一、man命令
在Linux 系统下,可以通过man命令来查看某一个Linux系统调用的帮助信息,man命令可以将该系统调用的详细信息显示出来,
使用方法:man # COMMAND
#可以代表数字1~8,一共8个章节。COMMAND表示要查询的函数
man 2 open如下:
从图中可以看到open函数需要包含什么头文件,以及open函数的具体用法。
二、文件描述符
在调用open函数打开一个文件成功的时候会返回一个非负整数,比如本应用中的fd1和fd2,文件描述符可分配的范围0~1023,其中0,1,2已经被系统占用了。
文件描述符的分配顺序是从小到大分配的。
当调用read/write函数对文件读写的时候,需要将文件对应的描述符传递给读写函数。
三、函数用法
1、open
open函数通常有以下2个基本用法:
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
pathname:字符串类型,用于标识需要打开或创建的文件,可以包含路径(绝对路径或相对路径)
flags:调用 open 函数时需要提供的标志,包括文件访问模式标志以及其它文件相关标志。
mode: 此参数用于指定新建文件的访问权限,只有当 flags 参数中包含 O_CREAT 或 O_TMPFILE 标志时才有效。
对于本应应用中flags和mode的解释,在注释中标注了
2、write
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
fd: 文件描述符。 关于文件描述符,前面已经给大家进行了简单地讲解,这里不再重述!我们需要将进行写操作的文件所对应的文件描述符传递给 write 函数。
buf: 指定写入数据对应的缓冲区。
count: 指定写入的字节数。
返回值: 如果成功将返回写入的字节数(0 表示未写入任何字节),如果此数字小于 count 参数,这不是错误,譬如磁盘空间已满,可能会发生这种情况;如果写入出错,则返回-1
3、read
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
fd: 文件描述符。与 write 函数的 fd 参数意义相同。
buf: 指定用于存储读取数据的缓冲区。
count: 指定需要读取的字节数。
返回值: 如果读取成功将返回读取到的字节数,实际读取到的字节数可能会小于 count 参数指定的字节数,也有可能会为 0,譬如进行读操作时,当前文件位置偏移量已经到了文件末尾。 实际读取到的字节数少于要求读取的字节数,譬如在到达文件末尾之前有 30 个字节数据,而要求读取 100 个字节,则 read 读取成功只能返回 30;而下一次再调用 read 读,它将返回 0。
4、close
#include <unistd.h>
int close(int fd);
fd:要关闭的文件的文件描述符
5、lseek
当打开文件时,会将读写偏移量设置为指向文件开始位置处,以后每次调用 read()、 write()将自动对其进行调整,以指向已读或已写数据后的下一字节
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
fd: 文件描述符。
offset: 偏移量,以字节为单位。
whence: 用于定义参数 offset 偏移量对应的参考值, 该参数为宏定义
SEEK_SET:读写偏移量将指向 offset 字节位置处(从文件头部开始算)
SEEK_CUR:读写偏移量将指向当前位置偏移量 + offset 字节位置处, offset 可以为正、也可以为负,如果是正数表示往后偏移,如果是负数则表示往前偏移;
SEEK_END:读写偏移量将指向文件末尾 + offset 字节位置处,同样 offset 可以为正、也可以为负,如果是正数表示往后偏移、如果是负数则表示往前偏移。
四、 运行测试
利用gcc编译链将该应用编译并执行:
如图所示实现了生成并拷贝内容的功能