前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >随笔水文——打开文件后会发生什么???

随笔水文——打开文件后会发生什么???

作者头像
比特大冒险
发布2023-04-16 17:09:27
发布2023-04-16 17:09:27
31300
代码可运行
举报
文章被收录于专栏:小白历险记小白历险记
运行总次数:0
代码可运行

前言

文件操作,这个熟悉而又陌生的词汇。在我们在图形化的电脑上,不断的双击打开很多不同的文件,且不关闭,你是否会好奇,OS它是如何打开管理这些不同的文件呢?

在不同的代码语言中,都会有文件操作的库函数来提供使用,它们的功能相仿,会不会有什么联系呢?


一、重新认识文件

文件这个在计算机里最常见的玩意,我们常用但是其概念很少被我们规范。

文件的基本构成粗略的概括可分为两部分:内容 + 属性。

内容不用解释大家都懂,属性一般包括该文件的创建、修改、类型、使用人、所在路径等一系列关于其的信息,用于记录和查看。

注:空文件当然也是有大小的,没有内容有属性

二、文件操作?

1、定义

        一般来说,我们第一次接触代码的文件操作是在C语言,例如:fopen、fclose、fread、fwrite等接口即是文件操作的函数。文件操作时我们必须open打开对应文件才能访问,而打开的文件会在相应的进程进行相应的操作。这就意味着 文件操作 = 打开的文件 + 相应的进程操作。

2、相关底层函数

        正如前言里说的,我们发现所有语言中都有相关的文件操作的库函数,且他们的用法和作用都大同小异,那是因为它们都是由基础的系统调用接口二次封装而来。

open close read write lseek这几个即为最初的系统调用接口。

我们拿open来做简绍

代码语言:javascript
代码运行次数:0
运行
复制
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
pathname: 要打开或创建的目标文件
flags: 打开文件时,可以传入多个参数选项,用下面的一个或者多个常量进行“或”运算,构成flags。
参数:
O_RDONLY: 只读打开
O_WRONLY: 只写打开
O_RDWR : 读,写打开
这三个常量,必须指定一个且只能指定一个
O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限
O_APPEND: 追加写
代码语言:javascript
代码运行次数:0
运行
复制
返回值:
成功:新打开的文件描述符
失败:-1

3、文件描述符

        在open的返回值我们发现了一个有趣的名字“文件描述符”,而且根据返回值的类型我们知道了为int,为一个数。好神奇,为了了解它我们写了如下代码。

代码语言:javascript
代码运行次数:0
运行
复制
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>

#define FILE_NAME(number) "log.txt"#number 



int main()
{

    umask(0);//给创建文件的掩码

    int fd0 = open(FILE_NAME(1), O_WRONLY | O_CREAT | O_APPEND, 0666);
    int fd1 = open(FILE_NAME(2), O_WRONLY | O_CREAT | O_APPEND, 0666);
    int fd2 = open(FILE_NAME(3), O_WRONLY | O_CREAT | O_APPEND, 0666);
    int fd3 = open(FILE_NAME(4), O_WRONLY | O_CREAT | O_APPEND, 0666);
    int fd4 = open(FILE_NAME(5), O_WRONLY | O_CREAT | O_APPEND, 0666);


    printf("fd: %d\n", fd0);
    printf("fd: %d\n", fd1);
    printf("fd: %d\n", fd2);
    printf("fd: %d\n", fd3);
    printf("fd: %d\n", fd4);
    
    close(fd0);
    close(fd1);
    close(fd2);
    close(fd3);
    close(fd4);
    return 0;
}

 运行如下

如图中的这个文件描述符的本来面貌,我们也能猜出来应该是下表。

 但是有个问题,0、1、2不在了。我们加几行代码再运行

代码语言:javascript
代码运行次数:0
运行
复制
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>

#define FILE_NAME(number) "log.txt"#number 



int main()
{

    printf("stdin->fd: %d\n", stdin->_fileno);
    printf("stdout->fd: %d\n", stdout->_fileno);
    printf("stderr->fd: %d\n", stderr->_fileno);

    umask(0);//给创建文件的掩码

    int fd0 = open(FILE_NAME(1), O_WRONLY | O_CREAT | O_APPEND, 0666);
    int fd1 = open(FILE_NAME(2), O_WRONLY | O_CREAT | O_APPEND, 0666);
    int fd2 = open(FILE_NAME(3), O_WRONLY | O_CREAT | O_APPEND, 0666);
    int fd3 = open(FILE_NAME(4), O_WRONLY | O_CREAT | O_APPEND, 0666);
    int fd4 = open(FILE_NAME(5), O_WRONLY | O_CREAT | O_APPEND, 0666);


    printf("fd: %d\n", fd0);
    printf("fd: %d\n", fd1);
    printf("fd: %d\n", fd2);
    printf("fd: %d\n", fd3);
    printf("fd: %d\n", fd4);
    
    close(fd0);
    close(fd1);
    close(fd2);
    close(fd3);
    close(fd4);
    return 0;
}

结果如下:

我们找到了,0、1、2,它们分别是标准输入流、标准输出流和标准错误流,这三个文件是自动创建且打开的,它们规定了对应文件的输入输出和报错的方式,在不同类型的文件上(由相应的函数)替换这三个流即可,对不同的文件访问。而这个方式也叫“重定向”。

 由于上面3个流的存在,我们可以将所有的设备也当作不同的文件来进行不同的管理,而它们也有一个我们熟知的名字——驱动。也由于这个特性,就有一种思想,万物皆可文件。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-02-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 一、重新认识文件
  • 二、文件操作?
    • 1、定义
    • 2、相关底层函数
    • 3、文件描述符
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档