Linux-内存文件

1. 基础IO操作

1.1 c语言的IO接口

fopen:打开一个文件,按照指定方式

参数:filename 文件名,也可以是路径,mode:打开方式

返回打开的文件指针

fread:从指定流中读数据

参数:从FILE对象中读数据,每次读size字节大小的数据,最多读count次,读的数据写在buffer里 

返回实际读的数据个数

fwrite:把数据写到指定的流中

参数 :从buffer中读数据,每次读size字节大小的数据,最多读count次,读的数据写在stream里 

返回实际写的数据个数

fclose:关闭打开的文件

不同的语言,比如c,c++,java....都有对应的IO接口,语言的底层封装的其实都是操作系统对应的IO接口,在语言层面

好处有:使用方便,学习成本低,一套接口,在不同的操作系统下都可以使用,具有跨平台可移植性

1.2 Linux的IO接口

open:打开文件

参数:pathname 路径名称,flags:标记位,打开方式,mode:文件属性(新建)

flags: 打开文件时,可以传入多个参数选项,用下面的一个或者多个常量进行“或”运算,构成flags。

参数:

  • O_RDONLY: 只读打开
  • O_WRONLY: 只写打开
  • O_RDWR : 读,写打开     这三个常量,必须指定一个且只能指定一个
  • O_CREAT : 若文件不存在,则创建它。需要使用mode选项(0666-umask),来指明新文件的访问权限
  • O_APPEND: 追加写
  • O_TRUNC:清空写

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

读fd文件,写到buf里,读count字节

读buf内容,写到fd文件里,写count字节

关闭文件


2. 文件描述符fd

open函数返回值是int类型的fd,这个fd是什么呢?

我们在写代码,调用接口,然后文件被编译运行,形成进程,也就是进程在打开文件。

打开文件是进程在执行,打开文件,就是把文件从,磁盘加载到内存上,还需要一个标识符,让进程能够找到这个内存上的文件。这个标识符就是fd,file describe 文件描述符。通过fd,进程就能找到对应的文件,完成下面的操作。

一个进程,可能要打开多个文件,就会有多个fd,如何对fd进行管理呢?

而现在知道,文件描述符就是从0开始的小整数。当我们打开文件时,操作系统在内存中要创建相应的数据结构来 描述目标文件。于是就有了file结构体。表示一个已经打开的文件对象。而进程执行open系统调用,所以必须让进 程和文件关联起来。

每个进程都有一个指针*files, 指向一张表files_struct,该表最重要的部分就是包涵一个指针数组,每个元素都是一个指向打开文件的指针!所以,本质上,文件描述符就是该数组的下标。所以,只要拿着文件 描述符,就可以找到对应的文件

c库默认会打开3个文件:stdin标准输入,stdout标准输出,stderr标准错误

他们的fd分别对应0(键盘),1(屏幕),2(屏幕)

接下来新建的文件,就会从3开始,依次往下,

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


3. 文件重定向

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
int main()
{
    close(1);
    int fd = open("myfile", O_WRONLY | O_CREAT | O_TRUNC, 0666);
    if (fd < 0)
    {
        perror("open");
        return 1;
    }
    printf("fd: %d\n", fd);
    fflush(stdout);

    close(fd);
    exit(0);
}

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

那重定向的本质是什么呢?

可以使用系统提供的函数接口:dup2

使用这个函数也可以达到相同的效果

dup2(3,1);

文件重定向:

输出重定向open(O_WRONLY | O_CREAT | O_APPENT)stdout重定向到新目标
追加重定向open(O_WRONLY | O_CREASE | O_TRUNC)stdout重定向到新目标
输入重定向open(O_RDONLY )stdin重定向到新目标

stdout和stderr的使用区分

stdout是用来输出打印信息,stderr一般用来输出程序的报错记录

./proc > out.txt 2> err.txt

可以分开把stdou输出的内容重定向到out.txt,stderr输出的内容重定向到err.txt

./proc > all.txt 2>&1

把两个都输出到all.txt文件中

myshell实现文件重定向

//整体结构:创建子进程,由子进程获取指令,父进程判断完成的怎么样
//1.打印标识开头
//2.获取指令字符串
//3.分析字符串提取指令到grev[]
//4.部分指令的特殊处理,例如cd
//5.替换进程execvpe
//
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>

#define SIZE 1024
#define NUM 32

#define EMPTY 0
#define INPUTDIR 1
#define OUTPUTDIR 2
#define APPPUTDIR 3

int status_dir;

char str[SIZE];
char* _grev[NUM];
char _env[NUM][NUM];

char* getfile(char* str, int end)
{
    while(str[end] != ' ')
    {
        if(str[end] == '>')
        {
            if(str[end - 1] == '>')
            {
                status_dir = APPPUTDIR;
                str[end-1] = '\0';
                return &str[end+1];
            }
            status_dir = OUTPUTDIR;
            str[end] = '\0';
            return &str[end+1];
        }
        else if(str[end] == '<')
        {
            status_dir = INPUTDIR;
            str[end] = '\0';
            return &str[end+1];
        }
        else{
            end--;
        }
    }
    return NULL;
}

int main()
{
    int num_env = 0;
    status_dir = EMPTY;
    while(1)
    {
            //1.
            printf("[root$loadhost myshell]# ");
            fflush(stdout);
            //2.
            memset(str,SIZE,'\0');
            fgets(str, SIZE, stdin);
            int sz = strlen(str);
            str[sz - 1] = '\0';
            //3.
            int end = sz - 2;
            char* file_end = getfile(str, end);
            
            _grev[0] = strtok(str, " ");
            int index = 1;
            //4.
            if(strcmp(_grev[0],"ls") == 0)
            {
                _grev[index++] = (char*)"--color=auto";
            }
            if(strcmp(_grev[0], "ll") == 0)
            {
                _grev[0] = (char*)"ls";
                _grev[index++] = (char*)"--color=auto";
                _grev[index++] = (char*)"-l";
            }
            
            while(_grev[index++] = strtok(NULL, " "));
            if(strcmp(_grev[0], "cd") == 0)
            {
                if(_grev[1]) chdir(_grev[1]);
                continue;
            }
            if(strcmp(_grev[0], "export") == 0 && _grev[1])
            {
                memcpy(_env[num_env],_grev[1],strlen(_grev[1])+1);
                putenv(_env[num_env]);
                num_env++;
                continue;
            }
        pid_t id = fork();
        if(id < 0)
        {
            perror("fork");
            exit(1);
        }
        else if(id == 0)
        {
            //child
            //5
            int fd;
            switch (status_dir)
            {
                case INPUTDIR:
                    fd = open(file_end, O_RDONLY);
                    dup2(fd,0);
                    break;
                case OUTPUTDIR:
                    fd = open(file_end, O_WRONLY | O_CREAT | O_TRUNC, 0666);
                    dup2(fd,1);
                    break;
                case APPPUTDIR:
                    fd = open(file_end, O_WRONLY | O_CREAT | O_APPEND, 0666);
                    dup2(fd,1);
                    break;
                case EMPTY:
                    break;
                default:
                    printf("bug?\n");
                    break;
            }

            
            execvp(_grev[0], _grev);
            exit(2);
        }
        else {
            //father
            int status = 0;
            pid_t ret = waitpid(id, &status, 0);
            if(ret < 0)
            {
                printf("等待子进程失败\n");
                exit(2);
            }
            else{
                if(WIFEXITED(status))
                {
                    printf("子进程退出码:%d\n",WEXITSTATUS(status));
                }
                else if(WIFSIGNALED(status))
                {
                    printf("子进程终止信号:%d\n",WTERMSIG(status));
                }
            }
        }
    }
    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Selenium web自动化测试环境搭建

Selenium web自动化环境搭建主要要经历以下几个步骤&#xff1a; 1、安装python 在python官网&#xff1a;Welcome to Python.org&#xff0c;根据各自对应平台如&#xff1a;windows&#xff0c;下载相应的python版本。 ​ 下载成功后&#xff0c;点击安装包&#xff0c;一直…

解释一下“暂存区”的概念,在Git中它扮演什么角色?

文章目录 暂存区在Git中的概念与作用什么是暂存区&#xff08;Staging Area&#xff09;暂存区的位置和结构 暂存区在Git工作流程中的角色1. 分离工作区与版本库的交互示例代码与操作步骤示例1&#xff1a;将工作区的修改添加至暂存区 2. 控制提交内容的粒度示例2&#xff1a;分…

【Linux】虚拟机与Xshell及VS Code的连接

一、基础环境 虚拟机&#xff1a;VMware Workstation Pro 虚拟机镜像&#xff1a;ubuntu-18.04.5-desktop-amd64.iso 其他&#xff1a;Xshell 6、Xftp 6、Visual Studio Code 上述软件的安装操作不再赘述&#xff0c;CSDN上有大量的优秀博文&#xff0c;可参考&#xff1a;详细…

安装和部署maven

准备工作 maven下载地址&#xff1a;https://maven.apache.org/download.cgi 使用wget将maven包下载到linux环境上&#xff0c;/toos/ 目录下&#xff08;也可用迅雷&#xff09; wget https://dlcdn.apache.org/maven/maven-3/3.9.6/binaries/apache-maven-3.9.6-bin.tar.g…

小游戏贪吃蛇的实现之C语言版

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a;C语言 目录 游戏前期准备&#xff1a; 设置控制台相关的信息 GetStdHandle GetConsoleCursorInfo SetConsoleCursorInfo SetConsoleCu…

VSCode插件开发学习

一、环境准备 0、参考文档&#xff1a;VS Code插件创作中文开发文档 1、大于18版本的nodejs 2、安装Yeoman和VS Code Extension Generator&#xff1a; npm install -g yo generator-code 3、生成脚手架 yo code 选择内容&#xff1a; ? What type of extension do yo…

GPT-3.5 Turbo 的 temperature 设置为 0 就是贪婪解码?

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 将 GPT-3.5 Turbo 的 temperature 设置为 0 通常意味着采用贪婪解码&#xff08;greedy decoding&#xff09;策略。在贪婪解码中&#xff0c;模型在每一步生成文本时选择概率最高的词元&#xff0c;从…

微调Llama3实践并基于Llama3构建心理咨询EmoLLM

Llama3 Xtuner微调Llama3 EmoLLM 心理咨询师

LabVIEW多设备控制与数据采集系统

LabVIEW多设备控制与数据采集系统 随着科技的进步&#xff0c;自动化测试与控制系统在工业、科研等领域的应用越来越广泛。开发了一种基于LabVIEW平台开发的多设备控制与数据采集系统&#xff0c;旨在解决多设备手动设置复杂、多路数据显示不直观、数据存储不便等问题。通过RS…

基于STM32的蓝牙小车的Proteus仿真(虚拟串口模拟)

文章目录 一、前言二、仿真图1.要求2.思路3.画图3.1 电源部分3.2 超声波测距部分3.3 电机驱动部分3.4 按键部分3.5 蓝牙部分3.6 显示屏部分3.7 整体 4.仿真5.软件 三、总结 一、前言 proteus本身并不支持蓝牙仿真&#xff0c;这里我采用虚拟串口的方式来模拟蓝牙控制。 这里给…

42岁TVB男艺人曾靠刘德华贴钱出道,苦熬10年终上位

张颕康在无线&#xff08;TVB&#xff09;电视打滚多年&#xff0c;近年在《逆天奇案》第一、二辑凭扎实演技为人留下印象。他还是圈中出名的「爱妻号」&#xff0c;日前在访问期间&#xff0c;张颕康三句不离多谢太太。 较年长的观众或会记得&#xff0c;张颕康初出道以「刘德…

kettle从入门到精通 第五十三课 ETL之kettle MQTT/RabbitMQ consumer实战

1、上一节课我们学习了MQTT producer 生产者步骤&#xff0c;MQTT consumer消费者步骤。该步骤可以从支持MRQTT协议的中间件获取数据&#xff0c;该步骤和kafka consumer 一样可以处理实时数据交互&#xff0c;如下图所示&#xff1a; 2、双击步骤打开MQTT consumer 配置窗口&a…

Today At Apple Notes

文章目录 2024.04.15 Phone15 入门2024.04.20 ipad 绘画 & 图片管理recreate 软件 绘画图片管理 官网&#xff1a; https://www.apple.com/today/Apple 亚洲第一大商店&#xff1a;Apple 静安零售店现已在上海开幕 2024.04.15 Phone15 入门 听课地点&#xff1a;上海区静…

如何对图片进行压缩和缩放

在手机像素越来越高的时代&#xff0c;照片的体积也在不断地膨胀&#xff0c;大部分情况下我们是不需要这么大的图片的&#xff0c;这个时候我们就需要对图片进行压缩或者缩放了&#xff0c;今天教大家如何缩小图片体积 打开智游剪辑&#xff08;官网: zyjj.cc&#xff09;&…

二维前缀和与差分

前言 延续前面所讲的一维前缀和以及差分&#xff0c;现在来写写二维前缀和与差分 主要这个画图就比前面的一维前缀和与差分复杂一点&#xff0c;不过大体思路是一样的 一维和二维的主要思路在于一维是只针对对一行一列&#xff0c;而二维是针对与一个矩阵的 好吧&#xff0…

OpenStack 常见模块详解

目录 一、OpenStack 架构 二、控制台 Dashboard 三、身份认证服务 Keystone 1&#xff09;用户&#xff08;user&#xff09; 2&#xff09;项目&#xff08;project&#xff09; 3&#xff09;角色&#xff08;role&#xff09; 4&#xff09;服务&#xff08;serv…

JavaCard学习笔记: CAP Component 之 Class Component

文章目录 整体结构tag和size字段signature_pool_length和signature_pooltype_descriptor结构导入类型编码导入项签名示例导入类导入数组导入远程方法 interfaces[]interface_info结构flagsinteface_countsuperinterfacesinterface_name class_info_compact classes[]结构flagsi…

wasm 系列之 WebAssembly 和 emscripten 暴力上手

wasm 是什么&#xff1f; wasm 是 WebAssembly 的缩写。wasm 不是传统意义上的汇编语言&#xff0c;而是一种编译的中间字节码&#xff0c;可以在浏览器和其他 wasm runtime 上运行非 JavaScript 类型的语言&#xff0c;只要能被编译成 wasm&#xff0c;譬如 kotlin/wasm、Rus…

Linux嵌入式驱动开发-阻塞IO与非阻塞IO

文章目录 阻塞与非阻塞访问简介阻塞访问的实现等待队列等待队列头等待队列项从等待队列头添加/移除等待队列项等待唤醒等待事件API 非阻塞访问的实现轮询poll 函数原型可以返回的资源状态 阻塞与非阻塞访问简介 **IO&#xff1a;**Input/Output&#xff0c;也就是输入/输出&am…

2024mac苹果电脑如何清理磁盘空间?用什么软件最好

苹果电脑已成为我们日常生活和工作不可或缺的一部分。随着时间的推移&#xff0c;不论是办公文档、个人照片还是各式各样的应用程序&#xff0c;都会逐渐积累&#xff0c;导致电脑的磁盘空间日益紧张。对于用户来说&#xff0c;苹果电脑如何清理磁盘空间&#xff0c;以保持设备…