Linux:文件与fd(被打开的文件)

在这里插入图片描述
hello,各位小伙伴,本篇文章跟大家一起学习《Linux:文件与fd(被打开的文件)》,感谢大家对我上一篇的支持,如有什么问题,还请多多指教 !
如果本篇文章对你有帮助,还请各位点点赞!!!

话不多说,开始正题:

前置准备

问大家一个问题,空文件有没有大小?答案是有:

  • 文件 = 内容 + 属性
    即使一个文件是空文件,也只是没有内容而已,还是要有相关的属性如:名称、创建时间、权限……
  • 在访问任何一个文件之前,都必须打开它,为什么?
    想想在访问文件之前,文件在哪?没错,在磁盘上
  • 访问一个文件,是谁在访问?
    当我们写完一个有fopen的代码的时候,文件打开了吗?没有
    当我们将其转化为可执行文件的时候,文件打开了吗?没有
    当我们运行可执行文件的时候,文件打开了吗?当fopen运行结束,文件打开了!!
    所以,访问文件的是进程!!!
  • 进程是在内存当中的,本质上就是CPU在跑进程,但是文件在磁盘中,根据冯诺依曼原理,CPU只能跑内存上的数据,所以,要想访问文件,就必须把文件加载到内存当中,也就是说,打开文件,其实就是将文件加载到内存当中!!
  • 将一个文件加载到内存,无非就是加载属性或者内容嘛,一个进程能够打开一个文件,那么能打开多个文件吗?包的!那一个系统里那么多进程,岂不是非常多文件被打开?那么操作系统要不要对其进行管理呢?答案是肯定的!如何管理:先描述再组织!
  • 盲猜一手:在内核中:文件 = 内核数据结构 + 文件内容
  • 进程 = 内核数据结构 + 程序的代码和数据;和文件十分相像,所以结论:
    我们在研究打开的文件,是在研究进程和文件的关系!
  • 那没有被打开的文件呢?在哪里?在磁盘中!

以下是本文所要讲解的内容:

  1. 被打开的文件——内存
  2. 没有被打开的文件——磁盘
  3. 二者结合就是文件系统!

被打开的文件——内存

文件IO基础讲解

fopen有很多个选项:
在这里插入图片描述
首先讲解w:打开文件,若文件不存在会帮助我们创建文件;若文件存在,将会把原先的文件内容清空。
这个操作和命令行中的>输出重定向很相像,一样是清空原先文件内容,再将内容输出在文件中,但是若>右侧没有内容,相当于清空文件。

myfile.c:

#include <stdio.h>

int main()
{
   
   
    FILE *fp = fopen("log.txt", "w");
    if(fp == NULL)
    {
   
   
        perror("fopen");
        return 1;
    }

    char buffer[1024];
    const char *message = "hello";
    int i = 0;
    while(i < 10)
    {
   
   
        snprintf(buffer, sizeof(buffer),"%s: %d\n", message, i);
        fputs(buffer, fp);
        i++;
    }
    fclose(fp);

    return 0;
}

在这里插入图片描述
可以看到,执行了两次myfilelog.txt的内容并没有变化,那是当然!
要是把fopenw改为a
在这里插入图片描述
发现端倪了吧!其实a就是append的意思——追加,所以打印结果才会这样,追加并不会将原先的文件清空
在命令行中也有追加重定向>>
在这里插入图片描述
剩下的选项都比较简单就不讲了

三大流

一个程序在默认启动时给我们打开这三种输出输入流

  • stdin 标准输入 键盘
  • stdout 标准输出 显示器
  • stderr 标准错误 显示器

在这里插入图片描述
可以看到这三种输出流都属于FILE*,这不和fopen的返回值一模一样吗?
其实这三种输出流都是C语言给我们默认提供的

但是键盘、显示器都是硬件啊,怎么能联系在一起?
没错,我们语言层是不能直接与硬件层直接互通的,必须通过操作系统,才能实现互通
所以,我们所用的C文件接口,底层一定要封装对应的文件类系统调用!

系统调用接口

open:
在这里插入图片描述

  • 第一个参数pathname就是要打开文件的路径名称
  • 第二个参数flags就是标记位
    主要用得到标记位:在这里插入图片描述
    这些标记为其实都是些宏,对于flags看上去是一个整型int,实际上是一个32比特位的位图,而这些宏,实际上就是只有一个比特位为1的值

其实很好理解,看如下代码:

#include <stdio.h>

#define ONE (1<<0)
#define TWO (1<<1)
#define THREE (1<<2)
#define FOUR (1<<3)
#define FIVE (1<<4)

void Test(int flags)
{
   
   
    if(flags & ONE)
    {
   
   
        printf("ONE\n");
    }
    if(flags & TWO)
    {
   
   
        printf("TWO\n");
    }
    if(flags & THREE)
    {
   
   
        printf("THREE\n");
    }
    if(flags & FOUR)
    {
   
   
        printf("FOUR\n");
    }
    if(flags & FIVE)
    {
   
   
        printf("FIVE\n");
    }
}

int main()
{
   
   
    Test(ONE);
    printf("========================\n");
    Test(ONE | TWO);
    printf("========================\n");
    Test(ONE | TWO | THREE);
    return 0;
}

在这里插入图片描述
我们使用一下:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
   
   
    open("log.txt", O_WRONLY | O_CREAT);

    return 0;
}

在这里插入图片描述
文件是创建出来了,怎么权限是乱码啊?

要记住,我们上述使用的fopen是已经被包装好的函数,我们在这使用的open是系统级的调用接口,是不会帮助我们设置权限的,也没有权限去帮我们设置默认权限(因为都是系统级别),需要我们在创建的时候设置好默认权限!

怎么设置,我们上述参数还少了一个没讲哦,没错,就是mode_t mode,所以一般我们都建议使用三参数的open,除非你只读或只写并且文件存在,看如下代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
   
   
    open("log.txt", O_WRONLY | O_CREAT, 0666);// 一般建议在前面加0

    return 0;
}

在这里插入图片描述
权限变正常了,但是为什么不是我设置的0666的权限?这是因为权限掩码的问题:
在这里插入图片描述

在设置权限的时候,你设置的权限会按位与上权限掩码,然后取反,得到的结果就是最终的权限!

当然了umask也是可以改变的:
在这里插入图片描述

umask(0);

将其设置为0之后,我们设置的权限就是最终的权限:
在这里插入图片描述
要注意的是:你在程序里设置的umask并不会影响系统的umask,也就是说每个进程都会有属于自己的umask,继承于父进程的umask

你也可以修改系统的权限掩码:

umask 0777

剩下最后就是open的返回值:
在这里插入图片描述
返回值是一个文件描述符,并且是个int,那到底是什么呢?我们看一下:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
   
   
    int fd1 = open("log.txt", O_WRONLY | O_CREAT, 0666);
    if(fd1 < 0)
    {
   
   
        perror("open");
    }
    printf("fd1: %d\n", fd1
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值