Linux下编程I/O操作(一)
最近刚刚回国, 因为疫情的缘故在上海隔离. 闲来无事,想要复习复习Linux的相关知识, 最近看到了关于文件的I/O操作, 特来此记录一下, 以后忘记了也能看看.
Linux下的I/O 操作比较常用的有4个函数, 分别是: open(), read(),write(),close.()和windows下的fopen()之类的函数相似.
open()
函数原型如下:
#include <sys/stat.h>
#include <fcntl.h>
//函数原型
int open(const char* pathname, int flags, .../*mode_t mode*/);
//Returns file descriptor on success, or -1 on error
顾名思义, 这个函数是用来打开文件的,当文件打开成功时, 会返回一个int型文件描述符,以便后面的read(),write()使用.
现在让我们来分析分析其中的参数:
pathname : 文件名称或者是路径
flags: 这个参数意味着访问文件的模式,
第三个参数可有可无: 如果你要访问的文件不存在的话, 可以在flags(第二个参数)使用O_CREATE创建一个, 创建之后需要对该文件的一些访问权限进行初始化, 这第三个参数就是用来设置文件的访问权限的.
下面来看一下都有些什么标志(flags):
标志 | 用途 |
---|---|
O_RDONLY | 以只读的方式打开 |
O_WRONLY | 以只写的方式打开 |
O_RDWR | 以读写的方式打开 |
O_CLOEXEC | 设置 close-on-exec 标志 |
O_CREAT | 若文件不存在则创建之 |
O_DIRECT | 无缓冲的输出/输出 |
O_DIRECTORY | 如果pathname不是目录, 则失败 |
O_EXCL | 结合O_CREAT参数使用, 专门用于创建文件 |
O_LARGEFILE | 在32位系统中使用此标志打开大文件 |
O_NOATIME | 调用read()时,不修改文件最近访问的时间 |
O_NOCTTY | 不要让pathname成为控制终端 |
O_NOFOLLOW | 对符号链接不予解引用 |
O_TRUNC | 截断已有文件,使其长度为零 |
O_APPEND | 总在文件尾部追加数据 |
O_ASYNC | 当I/O操作可行时,产生信号同志进程 |
O_DSYNC | 提供同步的I/O数据完整性 |
O_NONBLOCK | 以非阻塞方式打开 |
O_SYNC | 以同步方式写入文件 |
下面介绍一下第三个参数中的可选项
标志 | 语义 |
---|---|
S_IRUSR | 用户可读 |
S_IWUSR | 用户可写 |
S_IRGRP | 用户组可读 |
S_IWGRP | 用户组可写 |
S_IROTH | 其他人可读 |
S_IWOTH | 其他人可写 |
上面的选项挑着用就行了, 我一般时这么写的:
mode_t open_perms = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH|;
//--rw-r-r
read()
函数原型如下:
#include <unistd.h>
//函数原型
ssize_t read(int fd, void *buffer, size_t count);
//Returns number of bytes read, 0 on EOF, or -1 on error
这个函数可以读取文件中的数据, 并且将数据保存在buffer中,以供使用.
并且这个函数会反悔读取了多少的字节数.
分析一下参数:
fd: open()函数返回的文件描述符.
buffer: 文件中的数据将被保存在这里.
count: 限制了一次读取多少字符,这与buffer的大小有关.
write()
#include <unistd.h>
//函数原型
ssize_t write(int fd,void *buffer, size_t count);
//Returns number of bytes written, or -1 on error
write的调用与read类似,只不过是将读取的buf写入到文件中罢了.
分析一下参数:
fd: open()函数返回的文件描述符.
buffer: buffer参数为要写入文件中数据的内存地址.
count: 为欲从buffer写入文件的数据自己数.
close()
函数原型:
#include <unistd.h>
int close(int fd);
//Returns 0 on success, or -1 on error
关闭文件,没什么可说的
lseek()
函数原型:
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
//Returns new file offset if successful, or -1 on error
这个函数是用来指定文件偏移量的。
对于每个打开的文件, 系统内核会记录其文件偏移量。文件偏移量是指执行下一个read()或write()操作的文件起始位置,会以相对于文件头部起始点的文件当前位置来表示。文件第一个字节的偏移量为0.
文件空洞(科普向)
如果程序的文件偏移量依然跨越文件结尾, 然后再执行I/O操作, 将会发生什么情况呢?
read()调用将会反回0, 表示文件结尾. 从文件结尾后到新写入数据见的这段空间被称为文件空洞. 从编程的角度来看,文件空洞中是存在字节的,读取空洞将返回以0填充的缓冲区.
模仿linux下CP命令
#include <stdio.h> //C标准库
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#define BUF_SIZE 1024
int main(int argc, char *argv[])
{
char BUF[BUF_SIZE];
ssize_t read_size;
if(argc < 3 || strcmp(argv[1],"--help") == 0)
{
printf("按以下格式输入: /.CP file_name1 file_name2\n");
exit(0);//进程退出
}
else
{
int inputfd = open(argv[1],O_RDONLY);
if(inputfd == -1)
{
printf("找不到该文件\n");
exit(0);
}
//经过测试 上下两行没有区别
// int open_flags = O_CREAT|O_TRUNC|O_WRONLY;
int open_flags = O_CREAT|O_TRUNC|O_RDWR;
//文件访问权限, --rw--rw--rw
mode_t file_perms = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
int outputfd = open(argv[2],open_flags,file_perms);
while((read_size = read(inputfd,BUF,BUF_SIZE)) > 0)
{
if(write(outputfd,BUF,read_size)!=read_size)
printf("没有完全复制\n");
}
if(read_size == -1)
{
printf("打开文件失败\n");
}
//关闭被复制的文件
close(inputfd);
close(outputfd);
}
}