前言
Linux 系统中,一切皆文件 在 Linux 中,扩展名对 Linux 内核并没有什么实际意义,但是可以用来人为区分不同的文件,方便用户使用。- 比如 .c 是C文件,.h是头文件一样,虽然在我们眼中有区别,但是在Linux中,他们都属于普通文件类型
今天我们来了解一下简单的文件I/O读写操作。
一、实现过程
1、创建hello.txt文件
-
①、参数1:要打开的文件【可以用绝对路径】
-
②、参数2:flags ,以下三个比较常用
-—— O_RDWR:以读写的方式打开文件
-—— O_CREAT:如果文件不存在,就创建该文件
-—— O_TRUNC:若文件存在,则长度被截为0【可以理解为清空文件中的内容】 -
③、参数3:0666【设置该文件的权限,0为8进制数的前导符号】
大家在创建文件的时候会发现创建出来的文件,他的实际权限和我们设定的不太一样,这个我们待会再来聊。 -
open() 函数如果执行成功,会返回一个指向该文件的文件描述符 fd
在运行最终代码的时候,会看到 fd = 3 ,是因为
操作系统默认会打开 0、1、2 这三个文件描述符
0:标准输入【默认是键盘】
1:标准输出【默认是屏幕】
2:标准出错【默认是屏幕】
而新建的文件描述符 fd,是当前可用的文件描述符中最小的非负整数,所以这里的 fd 为 3
//创建hello.txt文件
if((fd = open("hello.txt", O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
{
printf("Open/Create file %s failure: %s\n", FILE_NAME, strerror(errno));
return -1;
}
printf("Open/Create file %s fd[%d] successfully\n", FILE_NAME, fd);
2、写数据到hello.txt
- ①、往文件描述符 fd 指向的文件中,写入MSG_STR这个字符串,内容是【Hello World\n】,写入的长度为 strlen(MSG_STR) 字节大小
- ②、若执行写操作成功,write() 函数的返回值则是写入数据的字节大小
- ③、若执行写操作失败,write() 函数的返回值则是一个 < 0 的数
//写数据到hello.txt中
if ((rv = write(fd, MSG_STR, strlen(MSG_STR))) < 0)
{
printf("Write data to fd[%d] failure: %s\n", fd, strerror(errno));
goto cleanup;
}
printf("Write %dB data to fd[%d]: %s\n", rv, fd, MSG_STR);
3、从hello.txt中读数据
- ①、把 “ 文件描述符 fd 指向的文件 ” 中的内容读数据到 buf 中,读数据的长度为 sizeof(buf) 字节大小
- ②、若执行读操作成功,read() 函数的返回值则是读出的数据的字节大小
- ③、若执行读操作失败,read() 函数的返回值则是一个 <0 的数
//从hello.txt中读数据
lseek(fd, 0, SEEK_SET);
if ((rv = read(fd, buf, sizeof(buf))) < 0)
{
printf("Read data from fd[%d] failure: %s\n", fd, strerror(errno));
goto cleanup;
}
printf("Read %luB data from fd[%d]: %s\n", strlen(buf), fd, buf);
二、具体代码
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#define FILE_NAME "hello.txt"
#define BUF_LEN 1024
#define MSG_STR "Hello World\n"
int main(int argc, char **argv)
{
int fd = -1;
int rv = -1;
char buf[BUF_LEN];
memset(buf, 0, sizeof(buf));
//创建hello.txt文件
if ((fd = open(FILE_NAME, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
{
printf("Open/Create file %s failure: %s\n", FILE_NAME, strerror(errno));
return -1;
}
printf("Open/Create file %s fd[%d] successfully\n", FILE_NAME, fd);
//写数据到hello.txt中
if ((rv = write(fd, MSG_STR, strlen(MSG_STR))) < 0)
{
printf("Write data to fd[%d] failure: %s\n", fd, strerror(errno));
goto cleanup;
}
printf("Write %dB data to fd[%d]: %s\n", rv, fd, MSG_STR);
//从hello.txt中读数据
lseek(fd, 0, SEEK_SET);
if ((rv = read(fd, buf, sizeof(buf))) < 0)
{
printf("Read data from fd[%d] failure: %s\n", fd, strerror(errno));
goto cleanup;
}
printf("Read %luB data from fd[%d]: %s\n", strlen(buf), fd, buf);
cleanup:
close(fd);
return 0;
}
三、运行效果
好了,我们接着来聊新建的 hello.txt 文件的权限问题,为什么我在代码里设置的访问权限是0666(rw-rw-rw-),但是实际上创建的文件的权限却是0664(rw-rw-r–)呢?
这其实是权限掩码在搞鬼,我们使用命令
umask
就可以查看权限掩码了,可以看到我这的权限掩码是0002,那什么是权限掩码呢
大家都知道我们的权限码其实是3个8进制的数字组成的,如0777、0666。
权限掩码就是相当于把相应的权限给屏蔽掉了,我这里就是把其他组的用户的写权限给屏蔽掉了。
我们将 预设的访问权限 减去 权限掩码,得到的就是实际上创建文件时的访问权限。
0666 - 0002 = 0664 (get√)
总结
以上是对Linux文件读写的一些理解,如有写的不好的地方,还请各位大佬不吝赐教