Linux基础 IO

news2024/11/17 10:48:38

目录

一、文件操作

1.1 C语言文件操作

1.2 文件 系统调用接口 

1.2.1 open/close函数

1.2.2 write/read函数

 二、进程与文件

2.1 0&1&2 文件描述符

2.2 C语言FILE

2.3 (OS管理&进程找到) 被打开文件方法

2.3.1 struct file 描述文件属性(OS管理文件)

2.3.2 PCB成员 struct files_struct * files(进程找到文件)

三、重定向

3.1 文件描述符分配原则

3.2 重定向(close关闭法)

3.3 dup2()函数重定向

3.4 重定向指令(> < >>)

3.5 自我实现shell_pro 实现文件重定向指令功能


一、文件操作

1. 文件=内容 + 属性

2. 空文件在磁盘也占空间!

3. 文件操作对象: 内容和属性

4.标定一个文件,必须使用:文件路径 + 文件名

5.一个文件如果没有被打开,那么我们不能对文件进行操作!文件可以由进程代码需要+OS 打开文件!所以文件操作的本质是进程和被打开文件的关系。 

1.1 C语言文件操作

打开文件方式:

当用除带a的写入方式,C语言都会先清空文件!


文件函数:

另一篇C文件函数博客:C语言文件重点知识总结(冲冲冲)_不到满级不改名的博客-CSDN博客_c语言文件知识点总结


1.2 文件 系统调用接口 

OS完成文件的打开、写入、关闭!所有的函数都避免不开操作系统的系统调用!我们之前的C或其他编程语言文件函数都封装了系统调用接口!

1.2.1 open/close函数


int main()
{
  
  //设置掩码
  umask(0);
   
  //打开文件,返回值是文件标识符
  int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);
  printf("fd=%d\n",fd);

  //关闭文件
  close(fd);
  return 0;
}

第一个参数是文件名,默认创建在当前路径下,也可以指定!

第二个参数是文件的操作形式!

我们注意到第二个参数形式是以一种大写的英文字母组合形成的变量按位与传过去的!这些变量本质是宏定义的整数!它们如何判别操作? 本质是通过控制位图的0/1 来判断是否拥有某项功能!

第三个参数是文件的权限设置。掩码为0,0666代表文件权限为 rw-rw-rw!

返回值是文件描述符,一个文件一个文件描述符区分彼此!


1.2.2 write/read函数

文件有文本类和二进制类,语言决定了一个文本的内容类型! OS系统不管你的类型,它默认都是二进制类,他只关心你要写入的字符个数!


#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
int main()
{
  //close(1);

  //设置掩码
  umask(0);
  //打开文件,返回文件标识符
  int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);
  printf("fd=%d\n",fd);
  //向文件标识符文件写入
  char buffer[64];
  int cnt=5;
  while(cnt)
  {
    //格式化向指定流中写入
    sprintf(buffer,"%s%d\n","hello Linux! cnt=",cnt--);
    //这里强调一下\0是C语言字符串结束的标识并不是文件!所以写入文件的字符个数不要带上\0!
    write(fd,buffer,strlen(buffer)); 
  }
  //关闭文件
  close(fd);
  return 0;
}

读文件内容:

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
int main()
{
  //close(1);

  //设置掩码
  umask(0);
  int fd=open("log.txt",O_RDONLY);
  printf("fd=%d\n",fd);
  
  //读取文件内容
  char get_buffer[1024];
  int num=read(fd,get_buffer,sizeof(get_buffer)-1);
  printf("num=%d\n",num);
  //文件结尾不是以\0结束,读完文件后,我们要在字符串末尾加上\0!
  if(num>0) get_buffer[num]=0;
  printf("%s",get_buffer);
  
  //关闭文件
  close(fd);
  return 0;
}

 二、进程与文件

2.1 0&1&2 文件描述符

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

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

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main()
{
  char buf[1024];
  //从键盘读
  ssize_t s = read(0, buf, sizeof(buf));
  if(s > 0){
    buf[s] = 0;
  //写入显示器
   write(1, buf, strlen(buf));
  //写入显示器
   write(2, buf, strlen(buf));
 }
return 0;
}

 2.2 C语言FILE

我们的系统调用只认识文件描述服,任何程序语言文件操作都离不开系统调用!C语言的FILE是一个结构体,它的结构体成员一定包含了文件描述符!


C语言FILE 类型的三种stdin(标准输入键盘) stdout(标准输出显示器) stderr(标准错误->显示器) 分别包含了0,1,2文件描述符!

下面我们来测试一下:

//#...
int main()
{
    printf("stdin->fd=%d\n",stdin->_fileno);
    printf("stdout->fd=%d\n",stdout->_fileno);
    printf("stderr->fd=%d\n",stderr->_fileno);
  return 0;
}

键盘、显示器也是文件!在我们眼中,我们通过文件的描述符来表示键盘、显示器!

我们可以初步认识到Linux一切皆文件!


2.3 (OS管理&进程找到) 被打开文件方法

文件操作本质:进程和被打开文件的关系!

我们可以同时打开多个文件,文件如何知道自己的身份?进程如何知道哪些文件是自己打开的?

2.3.1 struct file 描述文件属性(OS管理文件)

file结构体中包含了大部分文件属性!其中里面包含了该文件的文件描述符!所以OS通过管理结构体file管理文件!

2.3.2 PCB成员 struct files_struct * files(进程找到文件)

每一个进程PCB中都有一个指向结构体files的指针!files内有一个struct file* 类型的数组,数组元素指向一个个描述文件属性的结构体file,这样进程就能找到自己打开的文件!


三、重定向

3.1 文件描述符分配原则

文件描述符会遍历struct file*数组,循序寻找数组中下标小且没有被占用的fd

下面我来测试一下:

//test
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd = open("log.txt", O_RDONLY);
if(fd < 0){
perror("open");
return 1;
}
printf("fd: %d\n", fd);
close(fd);
return 0;
}

//myfile
int main()
{
  //关闭描述符为0的文件
  close(0);
  //打开一个文件
  int fd = open("log.txt", O_RDONLY);
  if(fd < 0){
  perror("open");
  return 1;
  }
  printf("fd: %d\n", fd);//分配原则,最小且没被占用的下标为0!
  close(fd);
  return 0;
}


3.2 重定向(close关闭法)

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
int main()
{
  //关闭标准输出(显示器)
  close(1);
  //打开新文件
  int fd=open("myfile.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);
  //printf:向标准输出打印内容
  printf("fd=%d\n",fd);
  //向标准输出打印
  printf("hello Linux!");
  return 0;
}

 

 代码结果是内容没有写到显示器上而是写入了新打开的文件!这种改变标准输入\输出的现象我们称文件重定向

重定向图片描述:

 


 3.3 dup2()函数重定向

 图片描述:


代码测试输出重定向:

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
int main()
{
  int fd=open("myfile.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);
  //打开失败
  if(fd<0)
  {
    perror("open");
    exit(-1);
  }
  //重定向
  dup2(fd,1);
  printf("hello Linux!\n");
  fprintf(stdout,"fa=%d\n",fd);
  fflush(stdout);
  return 0;
}


3.4 重定向指令(> < >>)

1. > 和 < 分别代表重定向的方向,是从左到右还是从右到左
2. >> 和 << 代表追加,也就是不改变重定向目标文件原有的内容,追加在后面。


 3.5 自我实现shell_pro 实现文件重定向指令功能

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<assert.h>
#include<string.h>
#include<errno.h>
#include<sys/stat.h>
#include<fcntl.h>
#define NUM_SIEZ 1024
char Command_Line[NUM_SIEZ];
#define OPT_NUM 64
char* myargv[OPT_NUM];
int last_sigcode=0;
int last_exit_code=0;
#define NO_REDIR 0
#define IN_REDIR 1
#define OUT_REDIR 2
#define APPEND_REDIR 3
//宏函数判断字符是否为空格
#define check_space(start) do{while((*start)==' ') start++;}while(0)
int redirType=0;
char* redir_file=NULL;


void check_command()
{
    char* start=Command_Line;
    char* end=Command_Line+strlen(Command_Line);
    while(start < end)
    {
        //输入重定向
        if(*start=='<')
        {
            redirType=IN_REDIR;
            *start='\0';
            start++;
            check_space(start);
            redir_file=start;
        }
        //输出重定向
        else if(*start=='>')
        {
            *start='\0';
            start++;
            //追加
            if(*start=='>'){
                redirType=APPEND_REDIR;
                start++;
                check_space(start);
                redir_file=start;
            }
            //非追加
            else{
                redirType=OUT_REDIR;
                start++;
                check_space(start);
                redir_file=start;
            }
        }
        else
        {
            start++;
        }
    }
}
int main()
{
while(1)
{
    printf("[用户名@主机名  当前路径]$ ");
    fflush(stdout);
    char* str=fgets(Command_Line,sizeof(Command_Line)-1,stdin);//从标准输入获取字符串
    assert(str!=NULL);
    //"abcde\n" 让最后一个字符为NULL(0)!为后面命令数组结尾获取0!
    Command_Line[strlen(Command_Line)-1]=0;
    //检查是否为重定向!
    check_command();
    //以空格为分隔单位,获取命令与命令选项!
    myargv[0]=strtok(Command_Line," ");
    int i=1;
    if(strcmp(myargv[0],"ls")==0)
    {
        myargv[i++]="--color=auto";
    }
    while(myargv[i++]=strtok(NULL," "));
    if(myargv[0]!=NULL && myargv[1]!=NULL && strcmp(myargv[0],"cd")==0)
    {
        chdir(myargv[1]);
        continue;
    }
    if(myargv[0]!=NULL && myargv[1]!=NULL && strcmp(myargv[0],"echo")==0)
    {
        if(strcmp(myargv[1],"$?")==0)
        {
            printf("sigcode=%d exit_code=%d\n",last_sigcode,last_exit_code);
            continue;
        }
        else
        {
            printf("%s\n",myargv[1]);
            last_exit_code=0;
            last_sigcode=0;
            continue;
        }
    }
    //创建子进程
    pid_t id=fork();
    //重定向
    if(id==0)
    {
        switch(redirType)
        {
            case NO_REDIR: break;
            case IN_REDIR:
            {
                int fd=open(redir_file,O_RDONLY,0666);
                if(id<0)
                {
                    perror("open");
                    exit(errno);
                }
                dup2(fd,0);
                break;
            }
            case OUT_REDIR:
            case APPEND_REDIR:
            {
                int flag=O_WRONLY|O_CREAT;
                if(redirType==OUT_REDIR)
                {
                    flag|=O_TRUNC;
                }
                else
                {
                    flag|=O_APPEND;
                }
                int fd=open(redir_file,flag,0666);
                if(id<0)
                {
                    perror("open");
                    exit(errno);
                }
                dup2(fd,1);
                break;
            }
        }
        execvp(myargv[0],myargv);
        exit(1);//进程替换失败
    }
    else if(id>0)
    {
        int status=0;
        int ret=waitpid(id,&status,0);
        assert(ret>0);
        //恢复标准输出、输入
        redirType=0;
        last_sigcode=status&0X7F;
        last_exit_code=(status>>8)&0XFF;
    }
    else
    {
        printf("creat child process error!\n");
    }
}      
    return 0;
}


 子进程创建的时候,子进程会拷贝父进程的文字描述符数组并指向父进程打开的文件!进程具有独立性!子进程文件重定向并不影响父进程!也就是说文件只有一个,指向文件的指针可以有多数!

画图效果:我们改变子进程的重定向并不影响父进程!


 

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

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

相关文章

线性时变系统的PID控制-2

在线性时变系统的PID控制-1的基础上采用S函数进行Simulink仿真。被控对象的描述方式可变换为&#xff1a;在S函数中&#xff0c;采用初始化、微分函数和输出函数&#xff0c;即mdllnitializeSizes函数、mdIDerivatives函数和mdlOutputs函数。在初始化中采用sizes结构&#xff0…

力扣sql简单篇练习(三)

力扣sql简单篇练习(三) 1 查找重复的电子邮箱 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 SELECT Email FROM Person GROUP BY Email HAVING count(id)>21.3 运行截图 2 每个产品在不同商店的价格 2.1 题目内容 2.1.1 基本题目信息 2.1.2 示…

[经典的图像warping方法] Thin Plate Spline: TPS理论和代码详解

0. 前言 2022年没有新写什么博客, 主要精力都在搞论文. 今年开始恢复! 本文的目标是详细分析一个经典的基于landmark(文章后面有时也称之为控制点control point)的图像warping(扭曲/变形)算法: Thin Plate Spine (TPS). TPS被广泛的应用于各类的任务中, 尤其是生物形态中应用…

动态内存管理(C语言)

目录 为什么要存在动态内存分配 动态内存函数的介绍 malloc函数 free函数 calloc函数 realloc函数 常见的动态内存错误 对NULL指针解引用错误 对动态开辟的空间越界访问 对非动态开辟内存使用free释放 使用free释放一块动态开辟内存的一部分 对同一块动态内存多次释放 动态开辟…

客快物流大数据项目(一百零五):启动ElasticSearch

文章目录 启动ElasticSearch 一、启动ES服务端 二、​​​​​​​启动Kibana 启动ElasticSearch

【NI Multisim 14.0虚拟仪器设计——放置虚拟仪器仪表(频率计数器)】

目录 序言 &#x1f3ee;放置虚拟仪器仪表&#x1f3ee; &#x1f9e7;频率计数器&#x1f9e7; &#x1f973;&#x1f973;&#xff08;1&#xff09;“测量”选项组:参数测量区。 &#x1f973;&#x1f973;&#xff08;2&#xff09;“耦合”选项组:用于选择电流耦合方…

CSDN 的故障处理流程,实例分享

CSDN 的研发团队每隔一段时间会和大家分享团队的进展&#xff0c;请看&#xff1a; 2021 年年底的汇报 2022 年上半年的汇报 2022 年下半年的汇报 从上面的报告中大家可以看到&#xff0c;我们在取得进展的同时&#xff0c; 也碰到了很多问题&#xff0c;也有一些困惑。 我写了…

「链表」简析

前言 前言&#xff1a;研究一个数据结构的时候&#xff0c;首先讲的是增删改查。 文章目录前言一、链表简介1. 含义2. 节点组成3. 存储方式1&#xff09;数据在内存中的存储方式2&#xff09;单链表在内存中的存储方式3&#xff09;双链表在内存中的存储方式4&#xff09;循环链…

ZYNQ IP核之MMCM/PLL

锁相环&#xff08;Phase Locked Loop&#xff0c;PLL&#xff09;&#xff0c;一种反馈控制电路&#xff0c;对时钟网络进行系统级的时钟管理和偏移控制&#xff0c;具有时钟倍频、分频、相位偏移和可编程占空比的功能。 Xilinx 7系列器件中的时钟资源包含了时钟管理单元CMT&…

SAPIEN PrimalSQL 2023.1[x64] Crack

SAPIEN PrimalSQL 2023.1 使数据库查询开发和测试变得轻而易举&#xff0c;无论您的数据库类型或供应商如何。 通过单个工具支持多个数据库提供程序。 Access、SQL Server、SQL Server Compact、MySQL、Oracle、ODBC、OLEDB、Sybase 等。 使用Visual Query Builder构建复杂的…

maven基础

一、Maven基础 为什么要学习Maven&#xff1f; Maven作为依赖管理工具&#xff0c;能够管理大规模的jarjarjar包&#xff0c;使用MavenMavenMaven后&#xff0c;依赖对应的JarJarJar包&#xff0c;能够自动下载、方便、快捷切规范。Maven作为构建管理工具&#xff0c;当我们使…

HTTP实用指南

HTTP实用指南 01.初始HTTP 当我们在浏览器地址栏输入一个网址或者关键字&#xff0c;它会给我们跳转到对应的网页&#xff0c;在这一过程中&#xff0c;内部到底是怎么运作的&#xff1f; 总结上述图片过程&#xff0c;用流程图来表示&#xff0c;如下&#xff1a; 处理输入信…

【论文翻译】Semantic Graph Convolutional Networks for 3D Human Pose Regression

【iccv论文】https://openaccess.thecvf.com/content_CVPR_2019/papers/Zhao_Semantic_Graph_Convolutional_Networks_for_3D_Human_Pose_Regression_CVPR_2019_paper.pdf 【github】https://github.com/garyzhao/SemGCN 摘要 在本文中&#xff0c;我们研究了用于回归的图卷积网…

ANR触发机制分析

ANR是一套监控Android应用程序响应是否及时的机制&#xff0c;可以把发生ANR比作是引爆炸弹&#xff0c;那么整个流程包含三部分组成&#xff1a; 埋定时炸弹&#xff1a;system_server进程启动倒计时&#xff0c;在规定时间内如果目标应用进程没有干完所有的活&#xff0c;则…

QEMU之一调试uboot(vexpress-a9)

u-boot版本&#xff1a;u-boot-2017.05开发板&#xff1a;vexpress-a9&#xff08;没办法&#xff0c;目前看到的都是这个开发板&#xff0c;想QEMU调试tiny210,一直没看到怎么修改qemu&#xff09;编译u-boot&#xff1a;make ARCHarm CROSS_COMPILEarm-linux-gnueabi- vexpre…

Avast 发布免费的 BianLian 勒索软件解密器

安全软件公司 Avast 发布了 BianLian 勒索软件的免费解密器&#xff0c;以帮助恶意软件的受害者在不向黑客支付费用的情况下恢复锁定的文件。 在 2022 年夏天 BianLian 勒索软件的活动增加后大约半年&#xff0c;该威胁组织入侵了多个知名组织&#xff0c;解密器的可用性就出现…

swagger(前言技术)

目录 一、swagger简介 1.前后端分离的特点 2.在没有swagger之前 3.swagger的作用 4.swagger的优点 二、swagger入门 1.新建springboot项目 2.集成swagger 3.开发一个controller用于测试 5.启动服务&#xff0c;验证集成效果 三、swagger常用注解 四、swagger使用综…

2022年PTA行业研究报告

第一章 行业概况 PTA是精对苯二甲酸&#xff08;Pure Terephthalic Acid&#xff09;的英文简称&#xff0c;在常温下是白色粉状晶体, 无毒、易燃&#xff0c;若与空气混合&#xff0c;在一定限度内遇火即燃烧。 PTA是重要的大宗有机原料之一&#xff0c;广泛用于化学纤维、轻…

【数据结构入门】-线性表之顺序表(1)

个人主页&#xff1a;平行线也会相交 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 平行线也会相交 原创 收录于专栏【数据结构】 从今天开始&#xff0c;就正式进入数据结构的大门了&#xff0c;把握机会&#xff0c;好好学习&#xff0c;加油。 本文目录…

Arduino环境下对NodeMCU ESP8266将文件直接传入flash的三种方式

flash存储简答介绍 参考&#xff1a;https://www.elecfans.com/consume/572040.html flash存储器又称闪存&#xff08;快闪存储器&#xff09;&#xff0c;就其本质而言&#xff0c;flash存储器属于EEPROM&#xff08;电擦除可编程只读存储器&#xff09;类型。是一种长寿命的…