【Linux基础IO篇】系统文件接口(1)

【Linux基础IO篇】系统文件接口(1)

目录

  • 【Linux基础IO篇】系统文件接口(1)
      • 回顾C语言的文件接口
      • 系统文件I/O
        • open接口的介绍
      • open函数返回值
        • 文件描述符fd(小整数)
        • 文件描述符的分配规则
      • 重定向
      • dup2系统调用
      • 改进myshell,添加重定向功能

作者:爱写代码的刚子

时间:2023.11.1

前言:本篇博客是关于C语言文件接口的回顾,以及学习在Linux系统下关于文件的系统调用接口。


回顾C语言的文件接口

在本篇博客不详细介绍,可以参考我之前写的一篇博客:

文件操作有关知识

注意:C默认会打开三个输入输出流,分别是stdin,stdout,stderr,这三个流类型都是FILE* ,fopen返回值类型:文件指针

系统文件I/O

用系统接口模拟上面的文件接口

写入文件:

在这里插入图片描述

在这里插入图片描述

读取文件:

在这里插入图片描述

在这里插入图片描述

open接口的介绍

在这里插入图片描述

pathname:要打开或者要创建的目标文件

flag:打开文件时,可以传入多个参数选项,用一个或多个常量进行’或’运算,构成flags

参数

  • O_RDONLY: 只读打开
  • O_WRONLY: 只写打开
  • O_RDWR : 读,写打开

这三个常量,必须指定一个且只能指定一个

  • O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限
  • O_APPEND: 追加写
  • O_TRUNC:将文件原本的内容全部丢弃,文件大小变为0。

返回值

  • 成功:新打开的文件描述符
  • 失败:-1

我们可以参照flags参数的形式自己编写一个类似效果的代码:


#define ONE (1<<0) // 1
#define TWO (1<<1) // 2
#define THREE (1<<2) // 4
#define FOUR (1<<3) // 8void show(int flags)
{if(flags&ONE) printf("hello function1\n");if(flags&TWO) printf("hello function2\n");if(flags&THREE) printf("hello function3\n");if(flags&FOUR) printf("hello function4\n");
}int main()
{printf("-----------------------------\n");show(ONE);printf("-----------------------------\n");show(TWO);printf("-----------------------------\n");show(ONE|TWO);printf("-----------------------------\n");show(ONE|TWO|THREE);printf("-----------------------------\n");show(ONE|THREE);printf("-----------------------------\n");show(THREE|FOUR);printf("-----------------------------\n");
}

注意使用第三个函数参数mode_t mode时,需要考虑当前的权限掩码,如果需要屏蔽权限掩码,则需要将当前进程的掩码设为0(umask(0);)

在这里插入图片描述

st_mode也用到了mode_t类型的变量.

  • open 函数具体使用哪个,和具体应用场景相关,如目标文件不存在,需要open创建,则第三个参数表示创建文件的默权限。

  • write、read、close、lseek,类比C文件相关接口

open函数返回值

  • 系统调用和库函数,C语言中的库函数对系统调用接口进行了一系列封装,(如:fopen、fclose、fread、fwrite统称为库函数libc)

  • 而,open、close、read、write、lseek都属于系统调用接口

在这里插入图片描述

f#系列的函数,都是对系统调用函数的封装。

文件描述符fd(小整数)

0 & 1 & 2

  • Linux进程默认情况下会有3个缺省打开的文件描述符,分别是标准输入0, 标准输出1, 标准错误2.

  • 0,1,2对应的物理设备一般是:键盘,显示器,显示器

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

文件描述符就是从0开始的小整数。当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件。于是就有了file结构体。表示一个已经打开的文件对象。而进程执行open系统调用,所以必须让进程和文件关联起来。每个进程都有一个指针*files, 指向一张表files_struct,该表最重要的部分就是包涵一个指针数组,每个元素都是一个指向打开文件的指针!所以,本质上,文件描述符就是该数组的下标。所以,只要拿着文件描述符,就可以找到对应的文件

在这里插入图片描述

在这里插入图片描述

文件描述符的分配规则

实验(图片中的perror中的内容应该为open,当时写错了):

在这里插入图片描述

以上图片中我们关闭了显示器一号文件,再打开test.c,运行程序

在这里插入图片描述

在这里插入图片描述

以上结果中我们发现本来应该要向显示器显示的数据却打印到了文件中,说明新打开的文件将1作为了当前文件的文件描述符

结论在files_struct数组中,找到当前没有被使用的最小的一个下标,作为新的文件描述符。

重定向

在这里插入图片描述

在这里插入图片描述

将本来应该输出到显示器的文件写入到文件中

此时,我们发现,本来应该输出到显示器上的内容,输出到了文件test1.c当中,其中,fd=1。这种现象叫做输出重定向。常见的重定向:>、>>、<

重定向本质:

在这里插入图片描述

dup2系统调用

在这里插入图片描述

在这里插入图片描述
解释为什么’\n’不能刷新缓冲区,而是必须使用fflush函数手动刷新

  • 标准输出它本身是行缓冲,本来反斜杠N可以刷新,但是现在把它重定向到另外一个文件当中了,但普通文件是全缓冲,行缓冲就不生效了,所以说’\n‘就没用,flush是把它重新再刷新一下,全部的缓冲区就能刷出来了。

在这里插入图片描述

printf是C库当中的IO函数,一般往 stdout 中输出,但是stdout底层访问文件的时候,找的还是fd:1, 但此时,fd:1 下标所表示内容,已经变成了myfile的地址,不再是显示器文件的地址,所以,输出的任何消息都会往文件中写 入,进而完成输出重定向。

改进myshell,添加重定向功能

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <ctype.h>
#include <fcntl.h>#define LEFT "["
#define RIGHT "]"
#define LABLE "#"
#define DELIM " \t"
#define LINE_SIZE 1024
#define ARGC_SIZE 32
#define EXIT_CODE 44#define NONE -1
#define IN_RDIR     0
#define OUT_RDIR    1
#define APPEND_RDIR 2int lastcode = 0;
int quit = 0;
extern char **environ;
char commandline[LINE_SIZE];
char *argv[ARGC_SIZE];
char pwd[LINE_SIZE];
char *rdirfilename = NULL;
int rdir = NONE;// 自定义环境变量表
char myenv[LINE_SIZE];
// 自定义本地变量表const char *getusername()
{return getenv("USER");
}const char *gethostname1()
{return getenv("HOSTNAME");
}void getpwd()
{getcwd(pwd, sizeof(pwd));
}void check_redir(char *cmd)
{// ls -al -n// ls -al -n >/</>> filename.txtchar *pos = cmd;while(*pos){if(*pos == '>'){if(*(pos+1) == '>'){*pos++ = '\0';*pos++ = '\0';while(isspace(*pos)) pos++;rdirfilename = pos;rdir=APPEND_RDIR;break;}else{*pos = '\0';pos++;while(isspace(*pos)) pos++;rdirfilename = pos;rdir=OUT_RDIR;break;}}else if(*pos == '<'){*pos = '\0'; // ls -a -l -n < filename.txtpos++;while(isspace(*pos)) pos++;rdirfilename = pos;rdir=IN_RDIR;break;}else{//do nothing}pos++;}
}void interact(char *cline, int size)
{getpwd();printf(LEFT"%s@%s %s"RIGHT""LABLE" ", getusername(), gethostname1(), pwd);char *s = fgets(cline, size, stdin);assert(s);(void)s;// "abcd\n\0"cline[strlen(cline)-1] = '\0';//ls -a -l > myfile.txtcheck_redir(cline);
}int splitstring(char cline[], char *_argv[])
{int i = 0;argv[i++] = strtok(cline, DELIM);while(_argv[i++] = strtok(NULL, DELIM)); // 是=不是==return i - 1;
}void NormalExcute(char *_argv[])
{pid_t id = fork();if(id < 0){perror("fork");return;}else if(id == 0){int fd = 0;// 做了重定向的工作,后面在进行程序替换的时候并不影响if(rdir == IN_RDIR){fd = open(rdirfilename, O_RDONLY);dup2(fd, 0);}else if(rdir == OUT_RDIR){fd = open(rdirfilename, O_CREAT|O_WRONLY|O_TRUNC, 0666);dup2(fd, 1);}else if(rdir == APPEND_RDIR){fd = open(rdirfilename, O_CREAT|O_WRONLY|O_APPEND, 0666);dup2(fd, 1);}//让子进程执行命令//execvpe(_argv[0], _argv, environ);execvp(_argv[0], _argv);exit(EXIT_CODE);}else{int status = 0;pid_t rid = waitpid(id, &status, 0);if(rid == id) {lastcode = WEXITSTATUS(status);}}
}int buildCommand(char *_argv[], int _argc)
{if(_argc == 2 && strcmp(_argv[0], "cd") == 0){chdir(argv[1]);getpwd();sprintf(getenv("PWD"), "%s", pwd);return 1;}else if(_argc == 2 && strcmp(_argv[0], "export") == 0){strcpy(myenv, _argv[1]);putenv(myenv);return 1;}else if(_argc == 2 && strcmp(_argv[0], "echo") == 0){if(strcmp(_argv[1], "$?") == 0){printf("%d\n", lastcode);lastcode=0;}else if(*_argv[1] == '$'){char *val = getenv(_argv[1]+1);if(val) printf("%s\n", val);}else{printf("%s\n", _argv[1]);}return 1;}// 特殊处理一下lsif(strcmp(_argv[0], "ls") == 0){_argv[_argc++] = "--color";_argv[_argc] = NULL;}return 0;
}int main()
{while(!quit){// 1.rdirfilename = NULL;rdir = NONE;// 2. 交互问题,获取命令行, ls -a -l > myfile / ls -a -l >> myfile / cat < file.txtinteract(commandline, sizeof(commandline));// commandline -> "ls -a -l -n\0" -> "ls" "-a" "-l" "-n"// 3. 子串分割的问题,解析命令行int argc = splitstring(commandline, argv);if(argc == 0) continue;// 4. 指令的判断 // debug//for(int i = 0; argv[i]; i++) printf("[%d]: %s\n", i, argv[i]);//内键命令,本质就是一个shell内部的一个函数int n = buildCommand(argv, argc);// 5. 普通命令的执行if(!n) NormalExcute(argv);}return 0;
}

在这里插入图片描述

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

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

相关文章

JavaScript 中判断数据类型的多种方法

在 JavaScript 中&#xff0c;准确地判断一个数据的类型是非常重要的。这可以帮助我们更好地理解和操作数据&#xff0c;以及在编写代码时做出更明智的决策。 1.使用 typeof 运算符 typeof 运算符可以返回一个值的类型。但需要注意的是&#xff0c;它有一些局限性。例如&#…

Py之auto-gptq:auto-gptq的简介、安装、使用方法之详细攻略

Py之auto-gptq&#xff1a;auto-gptq的简介、安装、使用方法之详细攻略 目录 auto-gptq的简介 1、版本更新历史 2、性能对比 推理速度 困惑度&#xff08;PPL&#xff09; 3、支持的模型 3、支持的评估任务 auto-gptq的安装 auto-gptq的使用方法 1、基础用法 (1)、量…

《C语言从入门到精通》:入门容易,精通难,C语言也不例外

《C语言从入门到精通》&#xff1a;入门容易&#xff0c;精通难&#xff0c;C语言也不例外 C语言&#xff0c;容易上手&#xff0c;难以精通。它是一把双刃剑&#xff0c;既打开了编程世界的大门&#xff0c;又需要耐心与热情。无论是初学者还是专业人士&#xff0c;都需不断钻…

苹果cms论坛多播放源自动采集在线影视网站

苹果 cms 论坛一个基于 vue 和 gin 实现的在线观影网站 项目采用 vite vue 作为前端技术栈, 使用 ElementPlus 作为 UI 框架进行开发 后端程序使用 Gin gorm go-redis 等相关框架提供接口服务, 使用 gocolly 和 robfig/cron 进行公共影视资源采集和定时更新功能 目前用户…

java连接zookeeper

API ZooKeeper官方提供了Java API&#xff0c;可以通过Java代码来连接zookeeper服务进行操作。可以连接、创建节点、获取节点数据、监听节点变化等操作&#xff0c;具体有以下几个重要的类&#xff1a; ZooKeeper&#xff1a;ZooKeeper类是Java API的核心类&#xff0c;用于与…

vue 使用vue-office预览word、excel,pdf同理

在此&#xff0c;我只使用了docx和excel&#xff0c; pdf我直接使用的iframe进行的展示就不作赘述了 //docx文档预览组件 npm install vue-office/docx//excel文档预览组件 npm install vue-office/excel//pdf文档预览组件 npm install vue-office/pdf如果是vue2.6版本或以下还…

2.Spark的工作与架构原理

概述 目标&#xff1a; spark的工作原理spark数据处理通用流程rdd 什么是rddrdd 的特点 spark架构 spark架构相关进程spark架构原理 spark的工作原理 spark 的工作原理&#xff0c;如下图 图中中间部分是spark集群&#xff0c;也可以是基于 yarn 的&#xff0c;图上可以…

鲁班猫4(RK3588S)配置Realsense SDK和Realsense ROS(D435i T265)

0 环境 鲁班猫4开发板&#xff08;RK3588S&#xff09;Ubuntu 20.04 &#xff08;lubancat-rk3588-ubuntu20.04-gnome-20230829_update&#xff09;D435iT265ROS noeticRealsense SDK v2.53.1Realsense ROS v2.3.2 1 安装ROS 建议使用fishros.com的ROS一键安装 wget http:/…

为什么重写 redisTemplate

为什么重写 redisTemplate 1.安装 redis 上传 redis 的安装包tar -xvf redis-5.0.7.tar.gzyum -y install gcc-cmakemake PREFIX/soft/redis installcd /soft/redis/bin./redis-server redis.conf 2. 集成 redisTemplate maven 依赖 <dependency><groupId>org…

全国产EtherCAT运动控制边缘控制器(六):RtBasic文件下载与连续轨迹加工的Python+Qt开发

今天&#xff0c;正运动小助手给大家分享一下全国产EtherCAT运动控制边缘控制器ZMC432H如何使用PythonQT实现连续轨迹加工。 01 功能简介 全国产EtherCAT运动控制边缘控制器ZMC432H是正运动的一款软硬件全国产自主可控&#xff0c;运动控制接口兼容EtherCAT总线和脉冲型的独立…

编译 linux 内核 ubuntu 22.04 通过 编译降级内核版本

说的详细 http://kerneltravel.net/blog/2021/compile-kernel/ 也是 ubuntu 更为清爽 https://www.cnblogs.com/harrypotterjackson/p/11846222.html 较为简单的教程 https://www.51cto.com/article/663841.html https://blog.csdn.net/m0_61229668/article/details/1268505…

【WinForm详细教程五】WinForm中的MenuStrip 、ContextMenuStrip 、ToolStrip、StatusStrip控件

文章目录 1.MenuStrip2.ContextMenuStrip3.ToolStrip4.StatusStrip 1.MenuStrip MenuStrip作为一个容器可以包含多个菜单项。MenuStrip 的重要属性包括&#xff1a; Name&#xff1a;菜单的名字Dock&#xff1a;菜单的停靠位置Items&#xff1a;菜单项的集合 ToolStripMenuI…

华为云服务器,在线安装MySQL

需求 在华为云服务器上&#xff0c;部署MySQL数据库&#xff0c;通过 公网IP 访问数据库。 通过 yum &#xff0c;在线安装MySQL&#xff1b;配置远程连接&#xff0c;开放3306端口&#xff0c;能够通过公网访问。 云服务器配置说明 本文所使用的 华为云服务器 配置如下。 …

C++进阶语法——STL 标准模板库(上)(Standard Template Library)【学习笔记(六)】

文章目录 STL 标准模板库1、 STL简介2、STL容器的类别3、STL迭代器的类别4、STL算法的类别5、泛型编程&#xff08;generic programming&#xff09;6、C模板&#xff08;template&#xff09;6.1 函数模板&#xff08;function template&#xff09;6.2 类模板&#xff08;cla…

20231102从头开始配置cv180zb的编译环境(欢迎入坑,肯定还有很多问题等着你)

20231102从头开始配置cv180zb的编译环境&#xff08;欢迎入坑&#xff0c;肯定还有很多问题等着你&#xff09; 2023/11/2 11:31 &#xff08;欢迎入坑&#xff0c;本篇只是针对官方的文档整理的&#xff01;只装这些东西你肯定编译不过的&#xff0c;还有很多问题等着你呢&…

3.字符集和比较规则简介

3.字符集和比较规则简介 1.字符集和比较规则简介1.1 字符集简介1.2 比较规则简介1.3 一些重要的比较规则 2. MySQL 中支持的字符集和比较规则2.1 MySQL 的 utf8 和 utf8mb42.2 字符集查看2.3 比较规则查看 3. 字符集和比较规则的应用3.1 各级别的字符集和比较规则1. 服务器级别…

【求助啊】 计算机专业该何去何从啊

学校学习的东西跟不上社会的需求&#xff0c;马上要毕业了&#xff0c;来不及自学了&#xff0c;培训班唯一的出路吗&#xff1f;好像很多同学培训班培训后也找不到工作 进场打工吗 孔乙己脱不下的长衫啊&#xff0c; 专升本的 5 年了 学计算机5年还回去进程打工 感觉白读了啊…

Spring Boot面向切面加注解

一.项目pom.xml文件引入切面依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId> </dependency>二.定义注解类 import java.lang.annotation.*;/*** desc 错误日志注解* au…

AR眼镜定制开发-智能眼镜的主板硬件、软件

AR眼镜定制开发是一项复杂而又重要的工作&#xff0c;它需要准备相关的硬件设备和软件。这些设备包括多个传感器、显示装置和处理器等。传感器用于捕捉用户的动作和环境信息&#xff0c;如摄像头、陀螺仪、加速度计等;显示装置则用于将虚拟信息呈现给用户;处理器用于处理和协调…

京东科技埋点数据治理和平台建设实践 | 京东云技术团队

导读 本文核心内容聚焦为什么要埋点治理、埋点治理的方法论和实践、奇点一站式埋点管理平台的建设和创新功能。读者可以从全局角度深入了解埋点、埋点治理的整体思路和实践方法&#xff0c;落地的埋点工具和创新功能都有较高的实用参考价值。遵循埋点治理的方法论&#xff0c;…