• 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. 文件重定向

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. int main()
    7. {
    8. close(1);
    9. int fd = open("myfile", O_WRONLY | O_CREAT | O_TRUNC, 0666);
    10. if (fd < 0)
    11. {
    12. perror("open");
    13. return 1;
    14. }
    15. printf("fd: %d\n", fd);
    16. fflush(stdout);
    17. close(fd);
    18. exit(0);
    19. }

    此时,我们发现,本来应该输出到显示器上的内容,输出到了文件 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. //1.打印标识开头
    3. //2.获取指令字符串
    4. //3.分析字符串提取指令到grev[]
    5. //4.部分指令的特殊处理,例如cd
    6. //5.替换进程execvpe
    7. //
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. #include
    15. #include
    16. #define SIZE 1024
    17. #define NUM 32
    18. #define EMPTY 0
    19. #define INPUTDIR 1
    20. #define OUTPUTDIR 2
    21. #define APPPUTDIR 3
    22. int status_dir;
    23. char str[SIZE];
    24. char* _grev[NUM];
    25. char _env[NUM][NUM];
    26. char* getfile(char* str, int end)
    27. {
    28. while(str[end] != ' ')
    29. {
    30. if(str[end] == '>')
    31. {
    32. if(str[end - 1] == '>')
    33. {
    34. status_dir = APPPUTDIR;
    35. str[end-1] = '\0';
    36. return &str[end+1];
    37. }
    38. status_dir = OUTPUTDIR;
    39. str[end] = '\0';
    40. return &str[end+1];
    41. }
    42. else if(str[end] == '<')
    43. {
    44. status_dir = INPUTDIR;
    45. str[end] = '\0';
    46. return &str[end+1];
    47. }
    48. else{
    49. end--;
    50. }
    51. }
    52. return NULL;
    53. }
    54. int main()
    55. {
    56. int num_env = 0;
    57. status_dir = EMPTY;
    58. while(1)
    59. {
    60. //1.
    61. printf("[root$loadhost myshell]# ");
    62. fflush(stdout);
    63. //2.
    64. memset(str,SIZE,'\0');
    65. fgets(str, SIZE, stdin);
    66. int sz = strlen(str);
    67. str[sz - 1] = '\0';
    68. //3.
    69. int end = sz - 2;
    70. char* file_end = getfile(str, end);
    71. _grev[0] = strtok(str, " ");
    72. int index = 1;
    73. //4.
    74. if(strcmp(_grev[0],"ls") == 0)
    75. {
    76. _grev[index++] = (char*)"--color=auto";
    77. }
    78. if(strcmp(_grev[0], "ll") == 0)
    79. {
    80. _grev[0] = (char*)"ls";
    81. _grev[index++] = (char*)"--color=auto";
    82. _grev[index++] = (char*)"-l";
    83. }
    84. while(_grev[index++] = strtok(NULL, " "));
    85. if(strcmp(_grev[0], "cd") == 0)
    86. {
    87. if(_grev[1]) chdir(_grev[1]);
    88. continue;
    89. }
    90. if(strcmp(_grev[0], "export") == 0 && _grev[1])
    91. {
    92. memcpy(_env[num_env],_grev[1],strlen(_grev[1])+1);
    93. putenv(_env[num_env]);
    94. num_env++;
    95. continue;
    96. }
    97. pid_t id = fork();
    98. if(id < 0)
    99. {
    100. perror("fork");
    101. exit(1);
    102. }
    103. else if(id == 0)
    104. {
    105. //child
    106. //5
    107. int fd;
    108. switch (status_dir)
    109. {
    110. case INPUTDIR:
    111. fd = open(file_end, O_RDONLY);
    112. dup2(fd,0);
    113. break;
    114. case OUTPUTDIR:
    115. fd = open(file_end, O_WRONLY | O_CREAT | O_TRUNC, 0666);
    116. dup2(fd,1);
    117. break;
    118. case APPPUTDIR:
    119. fd = open(file_end, O_WRONLY | O_CREAT | O_APPEND, 0666);
    120. dup2(fd,1);
    121. break;
    122. case EMPTY:
    123. break;
    124. default:
    125. printf("bug?\n");
    126. break;
    127. }
    128. execvp(_grev[0], _grev);
    129. exit(2);
    130. }
    131. else {
    132. //father
    133. int status = 0;
    134. pid_t ret = waitpid(id, &status, 0);
    135. if(ret < 0)
    136. {
    137. printf("等待子进程失败\n");
    138. exit(2);
    139. }
    140. else{
    141. if(WIFEXITED(status))
    142. {
    143. printf("子进程退出码:%d\n",WEXITSTATUS(status));
    144. }
    145. else if(WIFSIGNALED(status))
    146. {
    147. printf("子进程终止信号:%d\n",WTERMSIG(status));
    148. }
    149. }
    150. }
    151. }
    152. return 0;
    153. }
  • 相关阅读:
    多线程批量下载ERA5逐日数据
    MySQL(3)
    JavaScript——WebAPI
    android recyclerView緩存數量 recycleview的缓存
    2023黑龙江大学计算机考研信息汇总
    【软件与系统安全笔记】五、内存破坏防御
    wxpython设计GUI:窗口Frame最大化、最小化、关闭及全屏显示的说明
    《Spring Guides系列学习》guide21 - guide25
    驱动获取设备树节点信息
    K8sGPT,基于 AI 的云原生终极工具
  • 原文地址:https://blog.csdn.net/bananawolf/article/details/137997882