文件IO
文件描述符
对于文件 IO 来说, 一切都是围绕文件操作符来进行的。 在 Linux 系统中, 所有打开的文件都有一个对应的文件描述符。
文件描述符的本质是一个非负整数, 当我们打开一个文件时, 系统会给我们分配一个文件描述符。
当我们对一个文件做读写操作的时候, 我们使用 open 函数返回的这个文件描述符会标识该文件,并将其作为参数传递给 read 或者 write 函数。 在 posix.1 应用程序里面, 文件描述符 0,1,2 分别对应着标准输入, 标准输出, 标准错误。
open函数
参数 flags 可选标志:
当参数flags=O_CREAT时,可以加上第三个参数mode表面权限
文件的权限
文件的访问权限我们可以使用数字来表示:
可执行 x ->1
可写 w ->2
可读 r ->4
例:
如果我们要表示可读可写,就是上述值的和,可读可写->6
代码
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main(int argc, char const *argv[])
{
int fd; // 文件描述符
fd = open("a.c", O_CREAT | O_RDWR, 0666); // 不存在就创建 可读可写模式 读写权限
if (fd < 0)
{
printf("open is error\n");
}
printf("fd is %d\n", fd);
return 0;
}
运行结果
发现问题: a.c的文件权限不是0666
open函数创建文件时的权限是我们设置的mode&~(umask)
即: 0666&~(0022)
110 110 110 & ~(000 010 010)
110 110 110 & 111 101 101
110 100 100 -> 6 4 4 -> rw - r-- r--
close函数
代码
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
int fd; // 文件描述符
fd = open("a.c", O_CREAT | O_RDWR, 0666); // 不存在就创建 可读可写模式 读写权限
if (fd < 0)
{
printf("open is error\n");
}
printf("fd is %d\n", fd);
close(fd);
return 0;
}
read函数
正常读
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
int fd; // 文件描述符
char buf[32]={0};
ssize_t ret;
fd = open("a.c", O_CREAT | O_RDWR, 0666); // 不存在就创建 可读可写模式 读写权限
if (fd < 0)
{
printf("open is error\n");
return -1;
}
printf("fd is %d\n", fd);
ret = read(fd, buf, sizeof(buf));
if(ret < 0)
{
printf("read is error\n");
return -2;
}
printf("buf is %s\n", buf);
printf("ret is %ld\n", ret);
close(fd);
return 0;
}
运行结果
生成的文件中最后多一个\n,所以一个9个字符
读到结尾再读一次
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
int fd; // 文件描述符
char buf[32]={0};
ssize_t ret;
fd = open("a.c", O_CREAT | O_RDWR, 0666); // 不存在就创建 可读可写模式 读写权限
if (fd < 0)
{
printf("open is error\n");
return -1;
}
// printf("fd is %d\n", fd);
ret = read(fd, buf, sizeof(buf));
if(ret < 0)
{
printf("read is error\n");
return -2;
}
printf("buf is %s\n", buf);
printf("ret is %ld\n", ret);
ret = read(fd, buf, sizeof(buf));
printf("ret is %ld\n", ret);
close(fd);
return 0;
}
运行结果
ret返回0表示已经读到文件末尾
write函数
代码
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
int fd; // 文件描述符
char *buf="hello\n";
ssize_t ret;
fd = open("a.c", O_CREAT | O_RDWR, 0666); // 不存在就创建 可读可写模式 读写权限
if (fd < 0)
{
printf("open is error\n");
return -1;
}
// printf("fd is %d\n", fd);
write(fd, buf, sizeof(buf));
close(fd);
return 0;
}
运行结果
综合练习
通过命令行操作,把a.c文件里面的内容写到b.c里面。
代码
open.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
int fd_src, fd_obj;
ssize_t ret = 0;
char buf[32];
if(argc != 3)
{
printf("Usage:%s <src file> <obj file>\n", argv[0]);
return -1;
}
fd_src = open(argv[1], O_RDONLY);
fd_obj = open(argv[2], O_CREAT|O_WRONLY, 0666);
while((ret = read(fd_src, buf, sizeof(buf))) != 0)
{
write(fd_obj, buf, ret);
}
close(fd_src);
close(fd_obj);
return 0;
}
运行结果
lseek函数
介绍
所有打开的文件都有一个当前文件偏移量(current file offset) ,以下简称为 cfo。
cfo 通常是一个非负整数, 用于表明文件开始处到文件当前位置的字节数。 读写操作通常开始于 cfo, 并且使 cfo 增大, 增量为读写的字节数。 文件被打开时, cfo 会被初始化为0, 除非使用了 O_APPEND 。 使用 lseek 函数可以改变文件的 cfo 。
成功返回当前指针位置
举个例子
把文件位置指针设置为 100 lseek(fd,100,SEEK_SET);
把文件位置设置成文件末尾 lseek(fd,0,SEEK_END);
确定当前的文件位置 lseek(fd,0,