文件描述符与重定向

news2025/4/21 16:54:38

1. open系统调用

在 Linux 中, open() 系统调用用于打开一个文件或设备,并返回一个文件描述符,通过该描述符可以进行文件读写操作。open() 可以用于创建新文件或打开已存在的文件,具体行为取决于传递给它的参数。

需要包含的头文件:

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

函数原型: 

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

int creat(const char *pathname, mode_t mode);

参数解释: 

pathname: 要打开或创建的⽬标⽂件
flags: 打开⽂件时,可以传⼊多个参数选项,⽤下⾯的⼀个或者多个常量进⾏“或”运算,构成
flags。
参数:
O_RDONLY: 只读打开
O_WRONLY: 只写打开
O_RDWR : 读,写打开
这三个常量,必须指定⼀个且只能指定⼀个

O_CREAT : 若⽂件不存在,则创建它。需要使⽤mode选项,来指明新⽂件的访问
权限
O_APPEND: 追加写
返回值:
成功:新打开的⽂件描述符
失败:-1
mode 参数用于设置文件权限,通常只有在使用 O_CREAT 标志时才会使用。它指定文件的新权限,控制谁可以读取、写入和执行该文件。mode 是一个表示文件权限的整数,使用常量来组合不同的权限位。

常见的 mode 权限:

S_IRUSR:用户可读权限。
S_IWUSR:用户可写权限。
S_IXUSR:用户可执行权限。
S_IRGRP:组用户可读权限。
S_IWGRP:组用户可写权限。
S_IXGRP:组用户可执行权限。
S_IROTH:其他用户可读权限。
S_IWOTH:其他用户可写权限。
S_IXOTH:其他用户可执行权限。
示例:
open("file.txt", O_CREAT, S_IRUSR | S_IWUSR);
这会创建一个新文件,并设置权限为文件所有者可读和可写。
也可以用二进制表示
open("myfile", O_WRONLY | O_CREAT, 00644);
文件所有者权限为读写。用户组和其他用户权限为只读。

myfile.c:

  • 打开文件
    使用 open() 函数以只读 (O_RDONLY) 和创建文件 (O_CREAT) 的模式打开 log.txt 文件。如果文件不存在,O_CREAT 会创建文件。若文件打开失败,程序会输出错误并返回 1。

  • 读取文件
    通过 read() 函数从文件描述符 fd 中读取数据到 buff 中。read() 函数将最多读取 strlen(msg) 字符(这是一个错误的参数,应该是缓冲区大小)。

  • 输出内容
    如果读取成功(s > 0),则通过 printf() 输出读取到的内容。否则,退出循环。

  • 关闭文件
    使用 close() 关闭文件描述符。

2. 文件描述符

2.1 文件描述符

文件描述符(File Descriptor,简称 FD)是操作系统为每个进程提供的一种标识符,用于访问打开的文件、设备或其他输入输出资源。文件描述符是一个非负整数,它在进程的文件表中对应着一个指向内核中文件信息的指针。

上面myfile.c中read之所以可以通过int类型的fd读取到long.txt文件的内容就是因为每个文件都有一个文件描述符。

文件描述符的工作原理

每个进程在打开文件时,操作系统会为该进程分配一个文件描述符。文件描述符不仅仅用于普通文件,还可以用于设备、管道和套接字等其他输入输出资源。操作系统通过文件描述符来管理文件的读写操作。

Linux进程默认情况下会有3个缺省打开的⽂件描述符,分别是:
  1. 标准输入(STDIN):文件描述符 0,用于从用户或其他程序读取数据。
  2. 标准输出(STDOUT):文件描述符 1,用于向用户或其他程序输出数据。
  3. 标准错误输出(STDERR):文件描述符 2,用于输出错误信息。

除了标准输入、输出和错误输出外,应用程序可以打开更多文件,操作系统会为每个打开的文件分配一个文件描述符。

打开文件与文件描述符

当你调用 open() 函数打开一个文件时,操作系统会返回一个文件描述符,这个描述符可以用于后续的文件操作(如读写)。

int fd = open("example.txt", O_RDONLY);

这行代码尝试以只读模式打开 example.txt 文件,并返回一个文件描述符 fd。之后,可以使用该文件描述符来执行文件读写操作。

文件描述符的使用

在文件描述符返回后,可以通过以下系统调用来进行操作:

  • read(fd, buffer, size):从文件描述符 fd 中读取最多 size 字节的数据到 buffer 中。
  • write(fd, buffer, size):向文件描述符 fd 写入 size 字节的数据。
  • close(fd):关闭文件描述符,释放操作系统资源。

文件描述符表

操作系统维护一个文件描述符表,每个进程有一个独立的文件描述符表。文件描述符表的每个条目指向一个内核中的文件表,该表保存了文件的详细信息(如文件位置指针、权限等)。通过文件描述符,操作系统可以访问这些信息。

示例:打开、读取、写入和关闭文件

  • 程序会从标准输入读取 Hello, World! 字符串并存储到 buf 中。
  • 标准输出write(1, ...) 会将 Hello, World! 输出到标准输出(屏幕)。
  • 标准错误输出write(2, ...) 会将相同的 Hello, World! 输出到标准错误(通常也是屏幕,但会有不同的标记或颜色,取决于终端设置)。

程序会从标准输入读取 hello henu 字符串并存储到 buf 中。

write(1, ...) 会将 hello henu 输出到标准输出(屏幕)。

write(2, ...) 会将相同的 hello henu 输出到标准错误(通常也是屏幕,但会有不同的标记或颜色,取决于终端设置)。

 2.2 文件描述符分配规则

标准文件描述符
在 Linux 和 Unix 系统中,每个进程默认会打开三个文件描述符,分别是:

这些文件描述符默认已经为进程打开,并且对应终端设备或其他输入输出流。

  • 标准输入(STDIN): 文件描述符 0
  • 标准输出(STDOUT): 文件描述符 1
  • 标准错误输出(STDERR): 文件描述符 2

从 3 开始的文件描述符

  • 当一个文件第一次通过 open() 打开时,它会获得文件描述符 3
  • 第二个文件会分配文件描述符 4,以此类推。
  • 除了标准输入、输出和错误输出外,进程还可以打开更多文件或设备。这些文件描述符的分配从文件描述符 3 开始,并且会根据文件打开的顺序逐个递增。

文件描述符的分配是按顺序进行的,并且不会跳过数字。

    1 #include <stdio.h>
    2 #include <sys/types.h>
    3 #include <sys/stat.h>
    4 #include <fcntl.h>
    5 
    6 int main()
    7 {
    8   int fd = open("myfile", O_RDONLY);
    9   if(fd < 0)
   10   {
   11     perror("open");
   12     return 1;
   13   }
   14   printf("%d\n", fd);                                                                                                                                                                                                          
   15 
   16   close(fd);
   17   return 0;
   18 }

关闭0或者2:
发现是结果是: fd: 0 或者 fd 2 ,可见,文件描述符的分配规则:在记录文件描述符的files_struct数组当中,找到当前没有被使用的最小的⼀个下标,作为新的文件描述符。

3. 重定向

如果将标准输出(1)关闭,会发生什么呢?

    1 #include <stdio.h>
    2 #include <sys/types.h>
    3 #include <sys/stat.h>
    4 #include <fcntl.h>
    5 #include <stdlib.h>
    6 
    7 int main()
    8 {
    9   close(1);
   10   int fd = open("log.txt", O_RDWR | O_CREAT, 00644); 
                                                        
   11   if(fd < 0)                                                                                                                                                                                                                   
   12   {
   13     perror("open");
   14     return 1;
   15   }
   16   printf("d: %d", fd);
   17   fflush(stdout);
   18 
   19   close(fd);
   20   return 0;
   21 }

 此时,我们发现,本来应该输出到显示器上的内容,输出到了文件 myfile 当中,其中,fd=1。这

种现象叫做输出重定向。常见的重定向有: > , >> , < 。

几个细节:

使用fflush  close(1);: 关闭了标准输出文件描述符,导致标准输出流会失效。而 fflush  则起到了一个作用,它会强制刷新缓冲区,并把缓冲区中的数据写入到文件或终端中。

open参数:第一个0表示这是八进制,第二个零是 特殊权限设置,644分别是文件所有者、所属组、其他用户的权限。

常见的几种重定向:
>:将标准输出重定向到文件,覆盖原文件内容。
>>:将标准输出重定向到文件,追加到文件末尾。
<:将文件内容作为标准输入提供给命令。
2>:将标准错误重定向到文件,覆盖原文件内容。
2>>:将标准错误追加到文件末尾。
&>:同时将标准输出和标准错误重定向到同一个文件,覆盖原文件内容。
>&:将标准输出和标准错误输出重定向到同一个文件,功能与 &> 类似。
2>&1:将标准错误重定向到标准输出,通常用于将两者合并到同一个文件。
那重定向的本质是什么呢?

4. dup2系统调用

dup2 是一个在 Unix-like 操作系统中用于文件描述符复制的系统调用。它可以将一个文件描述符复制到另一个指定的文件描述符,通常用于重定向输入输出。

参数: 

  • oldfd:现有的文件描述符,通常是一个已打开的文件或设备(如标准输入、标准输出等)。
  • newfd:目标文件描述符。dup2 会将 oldfd 的副本复制到 newfd,并关闭 newfd(如果它已经打开)。

返回值:

功能:

dup2 会将 oldfd 指向的文件或设备重定向到 newfd

如果 newfd 已经打开,dup2 会先关闭 newfd,然后将 oldfd 的文件描述符复制到 newfd

如果 oldfd 等于 newfddup2 不会做任何操作,只会返回 newfd

  1 #include <stdio.h>
  2 #include <sys/types.h>
  3 #include <sys/stat.h>
  4 #include <fcntl.h>
  5 #include <stdlib.h>
  6 #include <unistd.h>
  7 
  8 int main()
  9 {
 10   close(1);
 11   int fd = open("log.txt", O_RDWR | O_CREAT, 00644);//使用O_APPEND则是追加写入
 12   if(fd < 0)
 13   {
 14     perror("open");
 15     return 1;
 16   }
 17   dup2(fd, 1);
 18   while(1)                                                                                                                                                                                                                       
 19   {
 20     char buf[1024] = {0};
 21     ssize_t read_size = read(0, buf, sizeof(buf) - 1);
 22     if(read_size < 0)
 23     {
 24       perror("read");
 25       return 1;
 26     }
 27     printf("%s", buf);
 28     fflush(stdout);
 29   }
 30 
 31   return 0;
 32 }

返回值: 

  • 成功时,返回 newfd,即新的文件描述符。
  • 失败时,返回 -1,并设置 errno

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2308493.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于fast-whisper模型的语音识别工具的设计与实现

目录 摘 要 第1章 绪 论 1.1 论文研究主要内容 1.1.1模型类型选择 1.1.2开发语言的选择 1.2 国内外现状 第2章 关键技术介绍 2.1 关键性开发技术的介绍 2.1.1 Faster-Whisper数据模型 2.1.2 Django 第3章 系统分析 3.1 构架概述 3.1.1 功能构架 3.1.2 模块需求描述 3.2 系统开…

场内、场外期权怎么开户?期权佣金是多少?

期权交易需要一定的知识和经验&#xff0c;以有效管理风险和制定策略。 场内期权开户&#xff08;以50ETF为例&#xff09; 场内期权开户的各种方式大差不差&#xff0c;咱们就先以50ETF期权为例子看下。 场内期权开户条件包括&#xff1a; 首先是资金的要求&#xff0c;50万…

Linux:进程概念

目录 1 冯诺依曼体系 2 操作系统(Operator System) 3 如何理解管理 3.1计算机管理硬件 3.2 管理逻辑图 3.3 怎样管理 4 什么是进程&#xff1f; 5 查看进程 5.1 ps ajx显示所有进程信息 5.2 /proc(内存文件系统) 5.2.1 ls /proc/PID 5.2.2 ls /proc/PID -al ​ 5…

Rabbit MQ 高频面试题【刷题系列】

文章目录 一、公司生产环境用的什么消息中间件&#xff1f;二、Kafka、ActiveMQ、RabbitMQ、RocketMQ有什么优缺点&#xff1f;三、解耦、异步、削峰是什么&#xff1f;四、消息队列有什么缺点&#xff1f;五、RabbitMQ一般用在什么场景&#xff1f;六、简单说RabbitMQ有哪些角…

【NLP 28、一文速通NLP文本分类任务 —— 深度学习】

目录 一、深度学习 — pipeline 流水线 1.配置文件 config.py Ⅰ、路径相关 Ⅱ、模型相关 Ⅲ、训练相关 2.数据加载 loader.py Ⅰ、类初始化 Ⅱ、加载数据并预处理 Ⅲ、文本编码 Ⅳ、对输入序列截断或填充 Ⅴ、返回数据长度 Ⅵ、返回对应索引位置元素 Ⅶ、加载词表 Ⅷ、封装数据…

UnrealEngine UE5 可视化 从地球观察火星 金星 土星 运动轨迹

视频参考&#xff1a;https://www.bilibili.com/video/BV1KpXSYdEdo/ 从地球观察土星的运动轨迹 从地球观察火星 轨迹 从地球观察金星的运动轨迹

Rocky Linux 8.5 6G内存 静默模式(没图形界面)安装Oracle 19C

Oracle19c 下载地址 Database Software Downloads | Oraclehttps://www.oracle.com/database/technologies/oracle-database-software-downloads.html#db_ee 目录 一、准备服务器 1、服务器可以克隆、自己装 2、修改主机名 3、重启 4、关闭selinux 5、关闭防火墙 5.1、…

免费轻巧多功能 PDF 处理工具:转换、压缩、提取一应俱全

软件技术 今天要给大家分享一款超实用的 PDF 处理工具&#xff0c;它免费又轻巧&#xff0c;如同随时待命的得力小帮手&#xff0c;功能之强大超乎想象&#xff0c;真的值得大家收藏。 这款工具是绿色版软件&#xff0c;解压后开启&#xff0c;满满的 PDF 处理功能便映入眼帘…

基于ssm的校园跑腿管理系统+vue

作者主页&#xff1a;舒克日记 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 系统共有管理员、用户两个角色 管理员主要的功能用户信息管理、任务信息管理、任务类型管理、接单信息管理、公告信息管理、投诉信息管理、公告类型管…

java数据结构_Map和Set_9.1

1. 搜索树 1.1 概念 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是具有以下性质的二叉树&#xff1a; 若它的左子树不为空&#xff0c;则左子树上所有的结点都小于根结点的值若它的右子树不为空&#xff0c;则右子树上所有的结点都大于根结点的值…

横向移动靶场-Tr0ll: 3

Tr0ll: 3来自 <Tr0ll: 3 ~ VulnHub> 1&#xff0c;将两台虚拟机网络连接都改为NAT模式 2&#xff0c;攻击机上做namp局域网扫描发现靶机 nmap -sn 192.168.23.0/24 那么攻击机IP为192.168.23.182&#xff0c;靶场IP192.168.23.187 3&#xff0c;对靶机进行端口服务探测 …

记20忘10之六:line

记20忘10之六&#xff1a;line 胖子定律&#xff1a;每天坚持多咬两口&#xff0c;相信将来自己就是个胖子 今天&#xff0c;我们继续来记几个单词吧&#xff0c; line n.线 moral bottom line道德底线 派生、同源或相关&#xff1a; linear a.线的&#xff0c;直线的lineamen…

【愚公系列】《Python网络爬虫从入门到精通》036-DataFrame日期数据处理

标题详情作者简介愚公搬代码头衔华为云特约编辑,华为云云享专家,华为开发者专家,华为产品云测专家,CSDN博客专家,CSDN商业化专家,阿里云专家博主,阿里云签约作者,腾讯云优秀博主,腾讯云内容共创官,掘金优秀博主,亚马逊技领云博主,51CTO博客专家等。近期荣誉2022年度…

使用ChatGPT-Deep Reaserch两步给出文献综述!

文献综述是学术论文写作中不可或缺的一部分&#xff0c;它不仅是对已有研究的梳理和总结&#xff0c;更是为后续研究奠定理论基础的关键步骤。通过文献综述研究者能够全面了解当前研究领域的现状、主要观点和研究方法&#xff0c;从而找到自己研究的切入点和创新点。这一过程需…

从0开始的操作系统手搓教程14——进一步完成中断子系统

目录 所以&#xff0c;如何查看我们的IDT呢 改进我们的中断处理hook 对8253编程&#xff0c;提升系统的频率 导论 控制字说明 说一下每个方式——概论 说一说计数器如何进行计时 方式0 方式1 方式2 方式3 方式4 方式5 回到问题&#xff0c;我们如何设置单次触发冲…

Educational Codeforces Round 174 (Rated for Div. 2)

Problem - B - Codeforces 之前没思路&#xff0c;我看了看答案。 思路不就来了&#xff1a; 简而言之&#xff0c;BFS那样遍历周围&#xff08;上下左右均一次&#xff09;&#xff0c;如果有同色&#xff0c;就把这部分相邻的隔开&#xff0c;可以得到两块陌生人集合&#x…

微服务即时通信系统---(七)文件管理子服务

目录 功能设计 模块划分 业务接口/功能示意图 服务实现流程 服务代码实现 封装文件操作模块(utils.hpp) 获取唯一标识ID 文件读操作 文件写操作 编写proto文件 文件元信息 文件管理proto 单文件上传 多文件上传 单文件下载 多文件下载 RPC调用 服务端创建子…

mosfet的驱动设计-开关损耗

目录 1.开关时的DS损耗 2.导通损耗 3.截止损耗 4&#xff0e;驱动损耗 mos管的损耗主要有开关损耗和导通损耗两部分&#xff0c;开关损耗包括mos管开通是消耗的能量和在mos在线性区产生的损耗。导通损耗是由mos的导通电阻电阻消耗的能量。 mos的实际模型 我们先来感性的…

萌新学 Python 之 with 文件操作语句

with 语句用于资源管理&#xff0c;避免资源泄露&#xff0c;对文件操作时&#xff0c;不管文件是否有异常&#xff0c;都会自动清理和关闭 with 语句的格式&#xff1a; with open(文件路径, mode模式, encodingutf-8) as file_obj: # as 取别名print(对文件进行操作&…

C# Unity 唐老狮 No.2 模拟面试题

本文章不作任何商业用途 仅作学习与交流 安利唐老狮与其他老师合作的网站,内有大量免费资源和优质付费资源,我入门就是看唐老师的课程 打好坚实的基础非常非常重要: Unity课程 - 游习堂 - 唐老狮创立的游戏开发在线学习平台 - Powered By EduSoho 如果你发现了文章内特殊的字体…