Linux应用软件编程---文件操作3(文件IO及其指令、文件定位函数lseek、文件IO与标准IO的比较、缓冲区)
目录
一、文件IO
1、文件IO的操作指令
2、文件IO的打开方式
3、标准IO 和 文件IO 打开方式的对应关系
4、文件描述符
5、open 指令
1)需包含的头文件
2)指令说明
6、close 指令
1)需包含的头文件
2)指令说明
7、read 指令
8、write 指令
9、练习例题
1)使用 write 指令将数据输入 1.txt 文件中的练习
2)使用文件IO实现cat功能
3)使用文件IO实现copy功能
二、文件定位函数 (lseek)
1、函数概念
2、应用
三、标准IO与文件IO的对比
1、标准IO
2、文件IO
3、二者结构图
四、缓冲区
1、行缓冲
2、全缓冲
3、无缓冲
一、文件IO
文件IO(系统调用)是Linux内核专门为应用层提供的文件操作方法。
1、文件IO的操作指令
1)打开文件 open
2)读、写文件 read/write
3)关闭文件 close
2、文件IO的打开方式
打开方式 | 含义 |
O_RDONLY | 只读方式 |
O_WRONLY | 只写方式 |
O_RDWR | 可读可写 |
O_CREAT | 创建文件 |
O_TRUNC | 清空文件 |
O_APPEND | 追加写 |
3、标准IO 和 文件IO 打开方式的对应关系
标准IO | 文件IO |
“r” | O_RDONLY |
"r+" | O_RDWR |
"w" | O_WRONLY | O_CREAT | O_TRUNC |
"w+" | O_RDWR | O_CREAT | O_TRUNC |
"a" | O_WRONLY | O_APPEND | O_CREAT |
"a+" | O_RDWR | O_APPEND | O_CREAT |
*其中,文件IO 中的 “ | ” 是 “ 按位与 ” 运算符。
4、文件描述符
文件描述符是指操作系统中已打开文件的标识符。是一种小的、非负的整形数据
范围:0-1023 (总共1024个)
分配原则:最小未被使用原则(即从0开始往后,哪个部分没有被使用,先使用哪个部分)
文件描述符泄露:已打开的文件,使用完时,未及时关闭。
文件IO中的文件描述符的作用相当于标准IO中的文件流指针。
操作系统已经默认打开的三个文件占用了0、1、2这三个文件描述符:
标准IO | 含义 | 文件IO |
FILE * | -----------------> | int |
stdin | 标准输入设备 | 0 |
stdout | 标准输出设备 | 1 |
stderr | 标准出错设备 | 2 |
5、open 指令
1)需包含的头文件
#include <sys/types.h> |
#include <sys/stat.h> |
#include <fcntl.h> |
2)指令说明
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
功能:打开文件并获得一个文件描述符
参数:
pathname:要打开的文件的文件名
flags:打开方式
mode:文件读写执行操作权限(当flag中有O_CREAT标志时,必须要增加mode操作权限,为八进制书写格式)
返回值:
成功:文件描述符
失败:-1
*关于 mode 的计算方式为(mode & ~umask),mode 和 umask(码值) 的反 进行按位与操作,码值可通过在终端输入“ umask ” 进行查看。
例如:码值为 0002(000 000 000 010) 时
r w - r w - r - - (110 110 100) & ~(000 000 010)
1 1 0 1 1 0 1 0 0 --->0664
即“ rw-rw-r-- ” 权限的mode值为 0664。
6、close 指令
1)需包含的头文件
#include <unistd.h>
2)指令说明
int close(int fd);
功能:关闭文件
fd:使用open指令打开的文件
7、read 指令
ssize_t read(int fd, void *buf, size_t count);
功能:从文件中读取数据
参数:
fd:文件描述符
buf:存储数据的空间首地址
count:希望读取的字节数
返回值:
成功:实际读到的字节数
失败:-1
读到文件末尾:0
8、write 指令
ssize_t write(int fd, const void *buf, size_t count);
功能:向文件中写入数据
参数:
fd:文件描述符
buf:要写入的数据的首地址
count:要写入的字节数
返回值:
成功:实际写入的字节数
失败:-1
例如:在终端打印“ hello world ”,write代码为:write(1, "hello world", 11) 。
9、练习例题
下述例题均需包含以下头文件(封装为 “ head.h ” 头文件):
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
1)使用 write 指令将数据输入 1.txt 文件中的练习
#include "head.h"int main(int argc, const char *argv[])
{int fd = open("./1.txt", O_WRONLY | O_CREAT | O_TRUNC, 0664);if (-1 == fd){printf("open error\n");return -1;}char *pstr = "hello world";char str[32] = {"how are you"};write(fd, str, strlen(str));write(fd, "hello world", 11);write(fd, pstr, strlen(pstr));close(fd);return 0;
}
2)使用文件IO实现cat功能
#include "head.h"int main(int argc, const char *argv[])
{if (argc < 2){printf("Usage : ./a.out <filename>\n");return -1;}int fd = open(argv[1], O_RDONLY);if (fd < 0){printf("open error\n");return -1;}char buff[1024] = {0};while (1) //防止文件大于 1024 ,循环读取{ssize_t cnt = read(fd, buff, sizeof(buff));if (0 == cnt){break;}else if (-1 == cnt){printf("read error\n");break;}write(1, buff, cnt);}close(fd);return 0;
}
3)使用文件IO实现copy功能
#include "head.h"int main(int argc, const char *argv[])
{if (argc < 3){printf("Usage: ./a.out <srcfile> <dstfile>\n");return -1;}int fdsrc = open(argv[1], O_RDONLY);int fddst = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0664);if(-1 == fdsrc || -1 == fddst){printf("open error\n");return -1;}char buff[1024] = {0};while (1){ssize_t cnt = read(fdsrc, buff, sizeof(buff));if (cnt <= 0){break;}write(fddst, buff, cnt);}close(fdsrc);close(fddst);return 0;
}
二、文件定位函数 (lseek)
1、函数概念
off_t lseek(int fd, off_t offset, int whence);
功能:文件读写位置定位
参数:
fd:文件描述符
offset:偏移量(字节)
whence:要偏移的相对位置
SEEK_SET:文件开头位置
SEEK_CUR:文件当前读写位置
SEEK_END:文件末尾
返回值:
成功:返回当前读写位置到文件开头的偏移量
失败:-1
2、应用
例如: 求文件大小:
off_t len = lseek(fd, 0, SEEK_END);
l seek(fd, 0, SEEK_SET); //将指针指向文件开头 (复位)
#include "head.h"int main(int argc, const char *argv[])
{int fd = open("./1.txt", O_WRONLY | O_TRUNC | O_CREAT, 0664);if (fd < 0){printf("open error\n");return -1;}off_t offset = lseek(fd, 10, SEEK_SET); //从文件开头偏移10输入'A'printf("offset = %ld\n", offset);write(fd, "A", 1);offset = lseek(fd, 0, SEEK_CUR);//从当前位置偏移0printf("offset = %ld\n", offset);offset = lseek(fd, 0, SEEK_SET);//复位printf("offset = %ld\n", offset);offset = lseek(fd, 0, SEEK_END);//文件末尾printf("offset = %ld\n", offset);lseek(fd, 0, SEEK_SET); //复位close(fd);return 0;
}
三、标准IO与文件IO的对比
1、标准IO
1)属于C库函数,移植性强
2)标准IO是系统调用的一次封装,增加了缓冲区,目的是提高数据读写的效率
3)标准IO主要用在对普通文件的操作
2、文件IO
1)属于系统调用,只能用于Linux操作系统,移植性弱
2)文件IO无缓冲区
3)文件IO主要应用在对硬件的操作的,也可以操作普通文件
3、二者结构图
四、缓冲区
缓冲区分为 行缓冲、全缓冲、无缓冲 三部分。
1、行缓冲
大小默认为 1k(1024个字节),一般应用于:人机交互界面、终端
缓冲区被刷新的方法:
1)程序结束,自动刷新缓冲区
2)遇到\n刷新
3)fflush(文件流指针) 强制刷新
4)缓冲区满刷新
2、全缓冲
大小默认为 4k(4096个字节),一般应用于:文件缓冲区
缓冲区被刷新的方法:
1)程序结束,自动刷新缓冲区
2)fflush()强制刷新
3)文件关闭刷新
4)缓冲区满刷新
3、无缓冲
大小为 0k(0个字节),一般应用于:出错信息对应的设备
eg. stderr ---> 无缓冲
【END】