『Linux』文件描述符及重定向——为何说Linux下,一切皆文件?

这篇具有很好参考价值的文章主要介绍了『Linux』文件描述符及重定向——为何说Linux下,一切皆文件?。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

『Linux』文件描述符及重定向——为何说Linux下,一切皆文件?,Linux从入门到精通,linux,运维

💐专栏导读

🌸作者简介:花想云 ,在读本科生一枚,C/C++领域新星创作者,新星计划导师,阿里云专家博主,CSDN内容合伙人…致力于 C/C++、Linux 学习。

🌸专栏简介:本文收录于 Linux从入门到精通,本专栏主要内容为本专栏主要内容为Linux的系统性学习,专为小白打造的文章专栏。

🌸相关专栏推荐:C语言初阶系列C语言进阶系列C++系列数据结构与算法

💐文章导读

本章我们将深入学习Linux文件系统,深入理解文件操作的底层原理。首先我们将回忆在C语言阶段曾经学习过的文件操作相关函数,其次我们将认识何为文件描述符——OS管理进程对应文件的关键。最后,我们需要理解曾经只是了解过的重定向操作究竟在底层做了什么~

『Linux』文件描述符及重定向——为何说Linux下,一切皆文件?,Linux从入门到精通,linux,运维

🐧C语言中的文件操作

C语言大家可能都学习过,但是C语言中的文件操作却不经常被使用。我们先来回顾一下C语言中的文件操作。

🐦fopen函数

*FILE fopen (const char *path, const char *mode);

  • 参数path:指定打开的文件所在路径;

  • 参数mode:指定文件打开的方式,包含如下方式:

『Linux』文件描述符及重定向——为何说Linux下,一切皆文件?,Linux从入门到精通,linux,运维

🐦写文件

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
int fprintf(FILE *stream, const char *format, …);
int sprintf(char *str, const char *format, …);
int snprintf(char *str, size_t size, const char *format, …);

🔔示例代码

#include <stdio.h>

#define LOG "log.txt"

int main()
{
    // 以 ' w' (只写)的方式打开文件
    FILE* fp = fopen(LOG,"w"); 
    if(fp == NULL)
    {
        perror("fopen");
        return 1;
    }
	
    // 对文件进行操作
    const char* msg = "Hello World!";
    int cnt = 5;
    while(cnt)
    {
        fprintf(fp,"%s: %d\n",msg,cnt);
        cnt--;
    }
    
    // 关闭文件
    fclose(fp);
    return 0;
}

『Linux』文件描述符及重定向——为何说Linux下,一切皆文件?,Linux从入门到精通,linux,运维

🐦读文件

size_t fread (void *ptr, size_t size, size_t nmemb, FILE *stream);
int fscanf (FILE *stream, const char *format, …);
int sscanf (const char *str, const char *format, …);

🔔示例代码

#include <stdio.h>

#define LOG "log.txt"
int main()
{
	 // 打开文件
	 FILE* fp = fopen(LOG,"r");
	 if(fp == NULL)
	 {
	   perror("fopen");
	   return 1;
	 }
	 // 对文件进行操作
	 const char* msg = "Hello World!";
	 char str[1024];
	 while(fscanf(fp,"%s ",str) != EOF)
	 {
	   fprintf(stdout,"%s ",str);
	 }
     // 关闭文件
     fclose(fp);
	 return 0;
}

『Linux』文件描述符及重定向——为何说Linux下,一切皆文件?,Linux从入门到精通,linux,运维
上面我们只是简单回忆一下C语言的文件操作,若想更加详细的了解文件操作,请参考该文章:

  • C语言文件操作指南;

🐧系统文件I/O

文件操作并不是只存在于C语言的,Java,python等编程语言中同样存在文件操作,只不过方法不同而已。其实我们可以尝试在系统层面统一看待文件操作。

操作系统提供了许多系统调用接口,而我们在语言层面看到的例如fopenfwrite等还有其他语言相关函数都是对操作系统提供的文件相关的系统调用接口做了不同程度的封装而已。

接下来,我们就认识一个十分重要的系统调用接口——open

🐦open系统调用

open是操作系统为语言层提供的系统调用接口,其作用是打开文件。可以根据参数来指定文件打开的方式、文件以何种权限被打开等等。在fopen以及各类语言的文件操作中,底层必定使用了open系统调用接口。

函数形式

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

函数参数

  • pathname:指定打开的文件所在路径;
  • flags:指定以何种形式打开文件;
    • O_CREAT:若要打开的文件不存在,则创建之;
    • O_WRONLY:只对文件进行写入;
    • O_TRUNC:打开文件的时候会将文件原本的内容清空;
    • 更多标志位请参考man手册;
  • mode:指定文件被创建时的权限;

返回值

  • 成功返回大于等于0的值
  • 失败返回-1

🔔示例代码

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define LOG "log.txt"

int main()
{
	umask(0); // 将系统默认的掩码置0

  	int fd = open(LOG, O_CREAT | O_WRONLY | O_TRUNC, 0666);
  	if(fd == -1)
  	{
    	printf("fd: %d, errno: %d, errstring: %s\n", fd, errno, strerror(errno));
  	}

  	const char* msg = "aaabbb ";
  	int cnt = 5;

 	 while(cnt--)
  	{
    	write(fd, msg, strlen(msg));
  	}

  	return 0;
}

『Linux』文件描述符及重定向——为何说Linux下,一切皆文件?,Linux从入门到精通,linux,运维

🔔注意

打开文件时,我们指定文件的权限是666,但是实际查看该文件的权限是,却并不是我们想要的结果,如图所示。

原因其实是,该log.txt文件是预先创建好的。并不是程序运行时创建的,而openmode参数,仅当要打开的文件不存在时,需要自动创建才会生效。

int fd = open(LOG, O_CREAT | O_WRONLY | O_TRUNC, 0666);

『Linux』文件描述符及重定向——为何说Linux下,一切皆文件?,Linux从入门到精通,linux,运维

🐧文件描述符

上一小节中,我们知道在open函数打开一个文件时,如果成功,会返回一个大于等于0的数字;失败时,则返回-1。

其实所谓的大于等于0的数字,就是文件描述符。我们可以创建多个文件,并将这些文件描述符打印出来。

🔔示例代码

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

int main()
{
  umask(0); // 将系统默认的掩码置0

  int fd1 = open("log1.txt", O_CREAT | O_WRONLY | O_TRUNC, 0666);
  int fd2 = open("log2.txt", O_CREAT | O_WRONLY | O_TRUNC, 0666);
  int fd3 = open("log3.txt", O_CREAT | O_WRONLY | O_TRUNC, 0666);
  int fd4 = open("log4.txt", O_CREAT | O_WRONLY | O_TRUNC, 0666);

  // 跳过检查的步骤,默认打开文件肯定会成功
  printf("fd1: %d\nfd2: %d\nfd3: %d\nfd4: %d\n",fd1,fd2,fd3,fd4);
  return 0;
}

『Linux』文件描述符及重定向——为何说Linux下,一切皆文件?,Linux从入门到精通,linux,运维

可见,文件描述符就是从0开始的小整数,且文件描述符是随着打开文件的操作递增的。那么现在有两个问题:

  • 为什么文件描述符看起来好像是从3开始的,有什么特殊含义吗?
  • 文件描述符有什么作用?

我们首先来解决第一个疑问。

🐦fd 0、1、2去哪了

早在C语言阶段,我们就知道,一个程序运行时,有3个文件流是默认被打开的。它们就是:

  • 标准输入流(一般对应的物理设备是键盘);
  • 标准输出流(一般对应的物理设备是显示器);
  • 标准错误流(一般对应的物理设备是显示器);

而此刻我们也应该能猜到,0、1、2这三个文件描述符其实是被这三个文件所占据。这也印证了Linux下一切皆文件,向显示器打印其实就是向文件中写入。

所以输入输出还可以采用如下方式:

🔔示例代码

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

int main()
{
  char buf[1024];
  ssize_t s = read(0, buf, sizeof(buf)); // 0为标准输入流的文件描述符
  if (s > 0)
  {
    buf[s] = 0;
    
    write(1, buf, strlen(buf));// 1为标准输出流的文件描述符
    write(2, buf, strlen(buf));// 2为标准错误流的文件描述符
  }
  return 0;
}

🐦文件描述符的作用

我们知道文件其实是文件内容加属性,属性包含文件的大小、文件创建的时间、上一次修改的时间、文件的权限等。OS在管理文件时,需要在内存中创建相应的数据结构来描述文件,这就是file结构体,表示一个已经打开的文件对象。所以OS在管理文件时,只要找到了该文件所对应的struct_file对象,就能找到该文件的内容和属性。

运行起来的程序我们把它叫做进程,当一个进程执行open调用,必须先让进程与要操作的文件关联起来。每个进程都有一个指针 *file,该指针指向一张表files_struct。这张表中最重要的部分就是一个指针数组。数组的每个元素都是一个指向打开文件的指针

所以,本质上,文件描述符就是该数组的下标,所以,只要拿到了文件描述符,就能找到对应的文件!

『Linux』文件描述符及重定向——为何说Linux下,一切皆文件?,Linux从入门到精通,linux,运维

🐧文件描述符的分配规则

上面我们通过测试,发现创建一个新文件,该文件的文件描述符是从3开始依次递增的。那么当我们把前面打开的文件关掉之后,再创建一个新的文件,会对该文件的文件描述符有影响吗?

🔔示例代码

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define LOG "log.txt"

int main()
{
  umask(0); // 将系统默认的掩码置0
  close(0); // 关闭文件描述符0所对应的文件,也就是标准输入
  int fd = open(LOG, O_CREAT | O_WRONLY | O_TRUNC, 0666);
  // 省略检查的步骤...

  printf("%d\n",fd);
  return 0;
}

『Linux』文件描述符及重定向——为何说Linux下,一切皆文件?,Linux从入门到精通,linux,运维

如图所示,我们可以得出结论_

  • 文件描述符的分配规则:在files_struct数组当中,找到当前没有被使用的最小的一个下标,作为新的文件描述符。

🐧重定向

之前我们可能见过这样的操作——

echo "hello linux" > log.txt

>‘意为重定向,这条指令的含义是,将本应该在屏幕上打印的内容,输出重定向到log.txt中。

『Linux』文件描述符及重定向——为何说Linux下,一切皆文件?,Linux从入门到精通,linux,运维

那么这样的重定向操作是如何完成的呢?

🐦dup2系统调用

int dup(int oldfd);
int dup2(int oldfd, int newfd);

dup2系统调用的作用是,将newfd文件描述符所对应的文件进行关闭,然后make一个新的fd——oldfd(注意这里有点奇怪,新创建的fd反而叫做oldfd)。在files_struct数组中,将下标为oldfd所在的内容复制到newfd中。

有点看不懂?没关系,来看看这幅图——

  int fd = open(LOG, O_CREAT | O_WRONLY | O_TRUNC, 0666);
  dup2(fd,1);

『Linux』文件描述符及重定向——为何说Linux下,一切皆文件?,Linux从入门到精通,linux,运维

再来看一组测试代码~

🔔示例代码

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define LOG "log.txt"

int main()
{
  umask(0); // 将系统默认的掩码置0
  int fd = open(LOG, O_CREAT | O_WRONLY | O_TRUNC, 0666);
  // 省略检查的步骤...
  
  dup2(fd,1);
  printf("hello world!\n"); // 本来应该向屏幕上打印,现在转为向LOG中打印
  printf("hello world!\n");
  printf("hello world!\n");

  printf("%d\n",fd);
  return 0;
}

『Linux』文件描述符及重定向——为何说Linux下,一切皆文件?,Linux从入门到精通,linux,运维

经过测试,我们得出结论——

  • 所谓重定向,其本质就是更改进程中对应的文件描述符表的指向内容!

本章的内容到这里就结束了!如果觉得对你有所帮助的话,欢迎三连~

『Linux』文件描述符及重定向——为何说Linux下,一切皆文件?,Linux从入门到精通,linux,运维文章来源地址https://www.toymoban.com/news/detail-517449.html

到了这里,关于『Linux』文件描述符及重定向——为何说Linux下,一切皆文件?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Linux】基础IO(一) :文件描述符,文件流指针,重定向

    🍎 作者: 阿润菜菜 📖 专栏: Linux系统编程 是不是只有C/C++有文件操作呢?python、java、go等文件接口操作的方法是不太一样的,那如何理解这种现象?有没有统一的视角去看待所有的语言文件操作呢?—我们今天从系统视角去理解 ---- 实际都是通过系统调用来访问 文件=内

    2024年01月18日
    浏览(48)
  • <Linux> 基础IO(文件操作、文件描述符fd、重定向)

    1、空文件也要在磁盘占用 我们创建的文件,虽然里面并没有存放数据,但是文件属性也是数据,即便你创建一个空文件,也要占据磁盘空间 2、文件 = 文件内容 + 文件属性 文件内容就是真正写入的内容,文件属性就是文件名、文件大小、文件的权限、拥有者所属组…… 3、文

    2024年02月03日
    浏览(48)
  • 【Linux】基础IO_文件描述符与重定向

    环境:centos7.6,腾讯云服务器 Linux文章都放在了专栏:【 Linux 】欢迎支持订阅 相关文章推荐: 【Linux】冯.诺依曼体系结构与操作系统 【C/进阶】如何对文件进行读写(含二进制)操作? 【Linux】基础IO_文件操作 在前文中学习了open函数,我们知道 open函数的返回值就是文件描

    2024年02月03日
    浏览(73)
  • Linux学习之系统默认打开的文件描述符、重定向

    一个进程默认会打开标准输入、标准输出、错误输出三个文件描述符。可以在 /proc/PID/fd 里边可以看到打开文件的描述符,PID需要改成具体的 pid ,比如可以使用 A终端 输入 vim proctest 之后按下回车键。 打开一个vim编辑窗口。 再打开一个 B终端 ,输入 ps -aux | grep \\\'vim\\\' 查找一下

    2024年02月13日
    浏览(40)
  • 【Linux】基础IO----系统文件IO & 文件描述符fd & 重定向

    作者:დ旧言~ 座右铭:松树千年终是朽,槿花一日自为荣。 目标:了解在Linux下的系统文件IO,知道什么是文件描述符,什么是重定向 毒鸡汤:白日莫闲过,青春不再来。 专栏选自:Linux初阶 望小伙伴们点赞👍收藏✨加关注哟💕💕 最早我们在C语言中学习关于如何用代码

    2024年04月14日
    浏览(54)
  • [Linux]基础IO详解(系统文件I/O接口、文件描述符、理解重定向)

            hello,大家好,这里是bang___bang_ ,今天和大家谈谈Linux中的基础IO,包含内容有对应的系统文件I/O接口,文件描述符,理解重定向。    目录 1️⃣初识文件 2️⃣ 系统文件I/O接口 🍙open 🍙write 🍙read 🍙close 3️⃣文件描述符 🍙012 🍙内核中文件描述符的探究 🍙分配

    2024年02月12日
    浏览(38)
  • 【探索Linux】—— 强大的命令行工具 P.12(文件描述符 | 重定向 | 基础IO)

    前面我们讲了C语言的基础知识,也了解了一些数据结构,并且讲了有关C++的一些知识,也学习了一些Linux的基本操作,也了解并学习了有关Linux开发工具vim 、gcc/g++ 使用、yum工具以及git 命令行提交代码也相信大家都掌握的不错,上一篇文章我们了解了基础IO,文件操作,今天

    2024年02月08日
    浏览(51)
  • 【探索Linux】文件描述符 | 重定向 | 基础IO —— 强大的命令行工具 P.12

    前面我们讲了C语言的基础知识,也了解了一些数据结构,并且讲了有关C++的一些知识,也学习了一些Linux的基本操作,也了解并学习了有关Linux开发工具vim 、gcc/g++ 使用、yum工具以及git 命令行提交代码也相信大家都掌握的不错,上一篇文章我们了解了基础IO,文件操作,今天

    2024年02月08日
    浏览(51)
  • 【看表情包学Linux】文件描述符 | 重定向 Redirection | dup2 函数 | 缓冲区的理解 (Cache)

       🤣  爆笑 教程  👉 《看表情包学Linux》👈   猛戳订阅     🔥 💭 写在前面: 在上一章中,我们已经把 fd 的基本原理搞清楚了。本章我们将开始探索 fd 的应用特征,探索 文件描述符的分配原则。讲解重定向,上一章是如何使用 fflush 把内容变出来的,介绍 dup2 函数,

    2023年04月25日
    浏览(58)
  • USB键盘鼠标描述符及数据格式分析

            1:键盘的hid描述符如下,数据的输入断点为中断方式,当有键盘敲击事件时,会上报长度为8字节的数据描述符,描述符共有8字节的输入报告和1字节的输出报告。         0x05,0x01,// Global Generic Desktop         0x09,0x06,// Local KeyBoard         0xA1,0x01,// Main app

    2024年04月22日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包