【探索Linux】P.12(文件描述符 | 重定向 | 基础IO)

简介: 【探索Linux】P.12(文件描述符 | 重定向 | 基础IO)

前言

前面我们讲了C语言的基础知识,也了解了一些数据结构,并且讲了有关C++的一些知识,也学习了一些Linux的基本操作,也了解并学习了有关Linux开发工具vim 、gcc/g++ 使用、yum工具以及git 命令行提交代码也相信大家都掌握的不错,上一篇文章我们了解了基础IO,文件操作,今天博主带大家了解一下 —— 文件描述符及重定向, 下面话不多说坐稳扶好咱们要开车了!!!😍

一、open()函数返回值

在认识返回值之前,先来认识一下两个概念: 系统调用 和 库函数。上篇文章中我们提到的 fopen、fclose、fread、fwrite 都是C标准库当中的函数,我们称之为库函数(libc)。而, open、close、read、write、lseek 都属于系统提供的接口,称之为系统调用接口。

在Linux中,open()函数是用于打开文件的系统调用,它返回文件描述符。文件描述符是一个非负整数,用于唯一标识打开的文件。

open()函数的返回值有以下几种可能:

  • 如果成功打开文件,则返回一个新分配的文件描述符
  • 如果发生错误,返回-1,并可以使用全局变量errno获取具体的错误代码。

常见的错误代码包括:

  • EACCES:权限不足,无法访问指定文件。
  • ENOENT:文件不存在。
  • EISDIR:指定路径是一个目录。
  • EMFILE:进程已经达到了最大允许的打开文件数。
  • ENFILE:系统已经达到了最大允许的打开文件数。

使用时,我们一般需要检查open()函数的返回值是否为-1来判断是否出错,然后再根据具体的错误代码进行相应的处理。

二、文件描述符fd

1. 文件描述符的分配规则

文件描述符(File Descriptor)是一个整数,它用于标识一个进程打开的文件。在Unix/Linux系统中,每个进程都有一个文件描述符表(File Descriptor Table),用于管理打开的文件。文件描述符表是一个数组,每个元素表示一个打开的文件,而文件描述符就是数组的下标。

在Linux中,每个进程都有一个进程描述符(Process Descriptor)。进程描述符中包括一个文件描述符表,以及其他重要的信息,例如进程ID、进程状态等。当进程打开一个文件时,内核会从可用的文件描述符中选择一个最小的数字,并将其分配给该文件。这个数字就是文件描述符。

文件描述符一般从3开始分配,因为0、1、2已经被预留给标准输入、输出、错误了。当进程打开一个文件时,内核会从当前可用的文件描述符中选择一个最小的数字,并将其分配给该文件。如果所有的文件描述符都已经被占用,再次打开文件就会返回错误。

当进程关闭一个文件时,相应的文件描述符就会变为可用状态,可以重新分配给其他文件。文件描述符的数目是有限的,通常与操作系统的版本、硬件配置等有关。

🚨🚨注意:同一个进程中不同的文件描述符可以引用同一个文件,也就是说,打开同一个文件多次会得到不同的文件描述符。每个文件描述符都有自己的读写指针(File Offset),因此在不同的文件描述符上读写同一个文件,文件指针会互相独立,互不影响。

另外,在多进程编程中,父子进程共享文件描述符表。也就是说,如果一个进程打开了一个文件,并创建了一个子进程,那么子进程也会继承父进程的文件描述符表,包括已经打开的文件。这样,子进程就可以操作父进程已经打开的文件了。如果需要让子进程关闭父进程打开的文件,可以在fork()调用之后使用close()函数关闭不需要的文件描述符。

2. 文件描述符0、1、2

Linux进程默认情况下会有3个缺省打开的文件描述符,分别是标准输入0,标准输出1,标准错误2。这些文件描述符在进程启动时会自动打开,并与对应的设备文件关联起来。

具体来说:

  • 文件描述符0(stdin) 用于处理标准输入,也就是从键盘或管道中读取输入数据。
  • 文件描述符1(stdout) 用于处理标准输出,也就是将程序输出写入到屏幕上或者重定向到文件中。
  • 文件描述符2(stderr) **用于处理标准错误,也就是输出程序的错误信息到终端或者重定向到文件中。

这些文件描述符是预先打开的,因此无需使用open()函数来打开它们。使用时,可以直接使用文件描述符号码0、1、2来引用它们。

三、重定向

在Unix/Linux系统中,重定向是一种常用的操作,用于改变进程的标准输入、标准输出和标准错误输出的默认设备。通过重定向,可以将命令的输入来自文件,或者将输出和错误输出写入到文件中,而不是默认的终端设备

重定向可以使用以下符号进行操作:

  1. 标准输出重定向(>):使用大于号(>)将命令的标准输出写入到指定的文件中,并覆盖原有内容。如果文件不存在,则创建一个新文件。
    例如,将命令的输出写入到文件output.txt中:
command > output.txt

标准输出追加重定向(>>):使用双大于号(>>)将命令的标准输出追加写入到指定的文件中,而不覆盖原有内容。如果文件不存在,则创建一个新文件。

例如,将命令的输出追加写入到文件output.txt中:

command >> output.txt

标准错误输出重定向(2>):使用大于号加数字2(2>)将命令的标准错误输出写入到指定的文件中,并覆盖原有内容。如果文件不存在,则创建一个新文件。

例如,将命令的错误输出写入到文件error.txt中:

command 2> error.txt

标准错误输出追加重定向(2>>):使用双大于号加数字2(2>>)将命令的标准错误输出追加写入到指定的文件中,而不覆盖原有内容。如果文件不存在,则创建一个新文件。

例如,将命令的错误输出追加写入到文件error.txt中:

command 2>> error.txt

标准输入重定向(<):使用小于号(<)将命令的标准输入从指定文件读取。

例如,将命令的输入从文件input.txt中读取:

command < input.txt

除了文件外,重定向还可以使用特殊设备:

  • /dev/null:空设备文件,将输出或错误输出重定向到/dev/null时,数据会被丢弃,类似于黑洞。例如:
command > /dev/null   # 将命令的输出丢弃
command 2> /dev/null  # 将命令的错误输出丢弃

重定向操作可以组合使用,例如:

command1 > output.txt 2>&1

上述命令将命令command1的标准输出和标准错误输出都写入到文件output.txt中。

🚨🚨注意:重定向操作符(>、>>、2>、2>>、<)在使用时需要与命令之间有空格,否则会被当作命令的一部分处理。另外,重定向是由shell解释和处理的,不是由具体的命令实现的,因此在不同的shell中可能存在一些差异。

1. 重定向的本质

**重定向的本质是通过操作文件描述符来改变进程的输入输出。**当一个进程执行时,会从这三个文件描述符中读取输入或将输出写入其中。重定向就是改变这些文件描述符所对应的文件,从而改变进程的输入输出行为。

在重定向操作中,文件描述符0、1和2分别对应的是文件描述符表中的前三个元素,即0、1和2。通过操作文件描述符表,可以将文件描述符指向不同的文件或设备。

例如,当使用>符号重定向标准输出时,实际上是将文件描述符1所对应的文件更改为指定的文件。具体的操作步骤如下:

  1. 打开指定文件,获取其对应的文件描述符x。
  2. 将进程的文件描述符表中的1替换为x。

这样,当进程进行标准输出时,实际上是将数据写入到了指定的文件中。

类似地,其他重定向操作也是通过类似的方式改变文件描述符表中相应位置的文件描述符。

🚨🚨注意重定向操作只影响当前进程以及其子进程,不会影响其他进程。每个进程都有自己独立的文件描述符表,互不干扰。

⭕图解

2. dup2 系统调用函数

dup2是Unix/Linux系统提供的系统调用函数之一,用于复制文件描述符并将其关联到指定的文件描述符

使用dup2函数可以方便地进行文件描述符的重定向,实现输入输出的灵活控制

函数原型如下:

#include <unistd.h>
int dup2(int oldfd, int newfd);

参数说明:

  • oldfd:要被复制的文件描述符。
  • newfd:新的文件描述符,将与oldfd关联。

函数功能:

dup2函数将文件描述符oldfd复制到newfd,并返回一个新的文件描述符。如果newfd已经打开,则将先关闭它。新的文件描述符将继承oldfd的文件状态标志(例如,文件偏移量、文件访问模式等)。

函数返回值:

  • 成功时,返回新的文件描述符;失败时,返回-1,并设置errno变量来指示错误类型。

使用示例(输入重定向):

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main() {
    int fd = open("file.txt", O_RDONLY);  // 打开文件,获取文件描述符
    if (fd == -1) {
        perror("open");
        exit(EXIT_FAILURE);
    }

    int newfd = dup2(fd, STDOUT_FILENO);  // 将文件描述符复制到标准输出
    if (newfd == -1) {
        perror("dup2");
        exit(EXIT_FAILURE);
    }

    printf("Hello, world!\n");  // 标准输出已被重定向到文件

    close(fd);  // 关闭文件描述符
    close(STDOUT_FILENO);
    return 0;
}

上述示例代码中,首先使用open函数打开一个文件,并获取文件描述符fd。然后,使用dup2函数将文件描述符fd复制到标准输出的文件描述符(即1),返回新的文件描述符newfd。接下来,通过printf函数向标准输出写入内容,实际上是将数据写入到文件中。最后,关闭文件描述符和标准输出的文件描述符。

温馨提示

感谢您对博主文章的关注与支持!如果您喜欢这篇文章,可以点赞、评论和分享给您的同学,这将对我提供巨大的鼓励和支持。另外,我计划在未来的更新中持续探讨与本文相关的内容。我会为您带来更多关于Linux以及C++编程技术问题的深入解析、应用案例和趣味玩法等。如果感兴趣的话可以关注博主的更新,不要错过任何精彩内容!

再次感谢您的支持和关注。我们期待与您建立更紧密的互动,共同探索Linux、C++、算法和编程的奥秘。祝您生活愉快,排便顺畅!

目录
相关文章
|
2月前
|
网络协议 安全 Linux
Linux C/C++之IO多路复用(select)
这篇文章主要介绍了TCP的三次握手和四次挥手过程,TCP与UDP的区别,以及如何使用select函数实现IO多路复用,包括服务器监听多个客户端连接和简单聊天室场景的应用示例。
99 0
|
2月前
|
存储 Linux C语言
Linux C/C++之IO多路复用(aio)
这篇文章介绍了Linux中IO多路复用技术epoll和异步IO技术aio的区别、执行过程、编程模型以及具体的编程实现方式。
115 1
Linux C/C++之IO多路复用(aio)
|
4月前
|
缓存 安全 Linux
Linux 五种IO模型
Linux 五种IO模型
|
2月前
|
Linux C++
Linux C/C++之IO多路复用(poll,epoll)
这篇文章详细介绍了Linux下C/C++编程中IO多路复用的两种机制:poll和epoll,包括它们的比较、编程模型、函数原型以及如何使用这些机制实现服务器端和客户端之间的多个连接。
40 0
Linux C/C++之IO多路复用(poll,epoll)
|
4月前
|
图形学 开发者 存储
超越基础教程:深度拆解Unity地形编辑器的每一个隐藏角落,让你的游戏世界既浩瀚无垠又细节满满——从新手到高手的全面技巧升级秘籍
【8月更文挑战第31天】Unity地形编辑器是游戏开发中的重要工具,可快速创建复杂多变的游戏环境。本文通过比较不同地形编辑技术,详细介绍如何利用其功能构建广阔且精细的游戏世界,并提供具体示例代码,展示从基础地形绘制到植被与纹理添加的全过程。通过学习这些技巧,开发者能显著提升游戏画面质量和玩家体验。
205 3
|
4月前
|
存储 Unix Linux
Linux I/O 重定向与管道
【8月更文挑战第17天】重定向在Linux中改变命令I/O流向,默认有&quot;&gt;&quot;覆盖输出至文件及&quot;&gt;&gt;&quot;追加输出至文件末尾,便于保存结果;使用&quot;&lt;&quot;从文件读取输入而非键盘,高效处理数据。文件描述符如0(stdin)、1(stdout)、2(stderr)标识I/O资源,支持读写操作。管道以&quot;|&quot;连接命令,使前一命令输出成为后一命令输入,如排序用户或找出CPU占用最高的进程,构建复杂数据处理流程。
53 9
|
4月前
|
存储 Unix Linux
Linux I/O 重定向与管道
【8月更文挑战第14天】输出重定向可将命令结果存入文件,如`&gt;`覆盖写入或`&gt;&gt;`追加写入。输入重定向从文件读取数据,如`&lt;`代替键盘输入。这些操作利用文件描述符(如0:stdin, 1:stdout, 2:stderr)管理I/O。管道`|`连接命令,使前一命令输出作为后一命令输入,便于数据处理,如排序用户`sort -t: -k3 -n /etc/passwd | head -3`或查找CPU占用高的进程`ps aux --sort=-%cpu | head -6`。
48 4
|
4月前
|
Unix Linux Shell
Linux I/O 重定向简介
Linux I/O 重定向简介
45 2
|
3月前
|
Unix Linux
linux中在进程之间传递文件描述符的实现方式
linux中在进程之间传递文件描述符的实现方式
|
4月前
|
运维 Rust 监控
Linux高效运维必备:fd命令深度解析,文件描述符管理从此得心应手!
【8月更文挑战第23天】本文介绍了一款名为fd的命令行工具,该工具基于Rust语言开发,旨在以更直观的语法和更快的速度替代传统的`find`命令。通过本文,您可以了解到如何安装fd以及一些基本用法示例,比如使用正则表达式匹配文件名、排除特定目录等。此外,文章还展示了如何结合`ps`和`lsof`命令来查找特定文件并显示其文件描述符,从而帮助您更好地管理和监控Linux系统中的文件与进程。
163 0