内存文件管理

简介:

@[TOC]

前言

  • 本篇针对的是对打开文件的描写

文件基础常识

  1. 文件=文件内容+文件属性

文件内容:就是我们可以看到的文本内容

文件属性:文件的读写,运行权限,创建者,日志信息等

  1. 无论文件内容还是文件属性都是一种数据,在磁盘上都要占据内存

文件操作

  1. 文件操作=文件内容操作+文件属性的操作

文件内存操作:对文本内容进行修改等操作

文件属性操作:对文件属性的权限,日志信息等的操作

  1. 被打开的文件称为内存文件,未打开的称为磁盘文件

打开文件

  1. 打开文件:是将文件的内容和文件属性加载到内存。由冯诺依曼体系结构决定,cpu直接和内存进行交互。
  2. 打开文件是根据当前的需要打开某些文件,并不是打开所有文件
  3. 打开一个文件时就会创建一个文件结构体。

FILE结构体

struct _IO_FILE {
int _flags; /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags
//缓冲区相关
/* The following pointers correspond to the C++ streambuf protocol. */
/* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
char* _IO_read_ptr; /* Current read pointer */
char* _IO_read_end; /* End of get area. */
char* _IO_read_base; /* Start of putback+get area. */
char* _IO_write_base; /* Start of put area. */
最后修改时间
char* _IO_write_ptr; /* Current put pointer. */
char* _IO_write_end; /* End of put area. */
char* _IO_buf_base; /* Start of reserve area. */
char* _IO_buf_end; /* End of reserve area. */
/* The following fields are used to support backing up and undo. */
char *_IO_save_base; /* Pointer to start of non-current get area. */
char *_IO_backup_base; /* Pointer to first valid character of backup area */
char *_IO_save_end; /* Pointer to end of non-current get area. */
struct _IO_marker *_markers;
struct _IO_FILE *_chain;
int _fileno; //封装的文件描述符
#if 0
int _blksize;
#else
int _flags2;
#endif
_IO_off_t _old_offset; /* This used to be _offset but it's too small. */
#define __HAVE_COLUMN /* temporary */
/* 1+column number of pbase(); 0 is unknown. */
unsigned short _cur_column;
signed char _vtable_offset;
char _shortbuf[1];
/* char* _save_gptr; char* _save_egptr; */
_IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};

creat

创建文件,并给予初始权限,用8进制码表示,要考虑权限掩码

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int creat(const char *pathname, mode_t mode);

open

打开文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jEVfkQno-1666710207224)(./%E6%96%87%E4%BB%B6%E6%8F%8F%E8%BF%B0%E7%AC%A6.assets/image-20221024205906638-1666616347980-3.png)]

#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);
参数名 作用 注意点
pathname 打开的文件名+路径 路径有相对和绝对路径
mode 初始权限码; 最终权限=初始权限&(~权限掩码)
flags 打开文件的方式 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DPGcsjna-1666710207237)(./%E6%96%87%E4%BB%B6%E6%8F%8F%E8%BF%B0%E7%AC%A6.assets/image-20221024215608352-1666619769825-9.png)]
返回值 文件描述符 成功返回fd,失败返回-1

write

从一个buf,向fd写入count个字节

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0nqdezoe-1666710207239)(./%E6%96%87%E4%BB%B6%E6%8F%8F%E8%BF%B0%E7%AC%A6.assets/image-20221024211120620-1666617082062-5.png)]

#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);

返回代表实际读取的字符个数

read

向fd中读取cont字节到buf中

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UWeh69SG-1666710207240)(./%E6%96%87%E4%BB%B6%E6%8F%8F%E8%BF%B0%E7%AC%A6.assets/image-20221024211135611.png)]

#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);

进程和文件

  1. 文件是存放在磁盘,向文件写入的内容,最终会写入到磁盘里面,而只有OS可以操作磁盘,因此在语言层面上我们通过函数接口生成进程后,进程会通过相应的系统接口,让OS与磁盘进行交互。
  2. 文件的操作最终是进程对文件的操作
  3. 任何对硬件的操作都要贯穿OS

路径

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tok0IWDB-1666710207241)(./%E6%96%87%E4%BB%B6%E6%8F%8F%E8%BF%B0%E7%AC%A6.assets/image-20221018161933709-1666081174872-1.png)]

当前路径指工作路径

相对路径:相比于当前路径的位置:./xx

绝对路径是从根到当前位置的路径

修改路径

chdir:可以修改当前进程的工作路径

cat模拟

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ixevjK1p-1666710207243)(./%E6%96%87%E4%BB%B6%E6%8F%8F%E8%BF%B0%E7%AC%A6.assets/image-20221019194340586-1666179821867-1.png)]

封装接口

  1. 原生系统接口,使用成本非常高
  2. 直接使用单一系统接口语言,跨平台(window,linux,macos)服务不行。
  3. c语言解决跨平台问题:条件编译+穷举所有的底层接口

默认流

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZYohE8FH-1666710207244)(./%E6%96%87%E4%BB%B6%E6%8F%8F%E8%BF%B0%E7%AC%A6.assets/image-20221020192230131.png)]

OS管理文件

  1. OS要想管理一个对象,必然要先描述这个对象也就是生成特定的内核数据结构体。因此OS管理文件就要先描述文件之后再组织文件。
  2. 通过文件结构体描述文件,通过链表链接结构体,最终对文件的管理变成了对链表的增删查改。

文件描述符-fd

  1. 加载到内存中的文件,为了方便标识与管理,OS使用文件描述符fd进行标识内存文件
  2. 文件结构体中的 pf->_fileno
  3. 在进程中,通过一个指针数组和文件链表建立映射关系
  4. 对于指针数组的前3个元素默认是:标准输入,输出,错误流
  5. 当建立新的映射关系时,OS会遍历这个数组,将文件结构体地址存放在第一个为NULL数组元素,并返回数组下标,这也就是文件描述符为什么是一个整型。
  6. 当链表删除节点时,对于指针数组,其直接在对应下标赋值为NULL。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZeCQA4bL-1666710207246)(./%E6%96%87%E4%BB%B6%E6%8F%8F%E8%BF%B0%E7%AC%A6.assets/image-20221020195148382-1666266709374-1.png)]

c语言实现面向对象类

C语言的结构体中,一般我们只考虑成员变量,但是当我们引入函数指针时,这个结构体就可以模拟类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tM7H7iK5-1666710207247)(./%E6%96%87%E4%BB%B6%E6%8F%8F%E8%BF%B0%E7%AC%A6.assets/image-20221020203616340-1666269377455-3.png)]

而一旦我们引入了函数指针,那么我们就可以通过这个指针指向任意的符号要求的函数。

而我们我们外设也就是硬件,它们的读写技术肯定是不一样的,但是如果相同的接口,在函数体中的是读写逻辑,那么我们就可以实现一个函数指针指向多个外设。---这就是C++多态的前身。

linux下一切皆文件

对于硬件层,os总是将其看作文件,对于不同的硬件,只需要提供其特殊的文件读写方式,就可以实现以统一的视角处理硬件层。这称为虚拟文件系统

背景

  1. 对于不同的外设,他们的读写方式必然不相同,但是函数指针的泛型,这就可以通过同一个文件结构体,描述不同的外设。同时对于OS来说,它通过文件描述符就可以访问不同的外设,即OS以统一的视角管理不同的外设。
  2. 将外设抽象为一个文件结构体,对这个结构体进行管理和驱动层就可以映射到外设硬件身上。
  3. 我们称这种管理逻辑系统为虚拟文件系统(VFS)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SX76hnAw-1666710207249)(./%E6%96%87%E4%BB%B6%E6%8F%8F%E8%BF%B0%E7%AC%A6.assets/image-20221020205239615-1666270360933-5.png)]

重定向

  1. 重定向的本质是对文件描述符指针数组中元素的替换,以完成内存中数据的流出与流入方向的改变。
  2. 文件描述符的指针数组的前3个元素是默认的文件:标准输入流(0),标准输出流(1),标准错误流(2).
  3. 重定向后,会改变缓存区的刷新策略

输出重定向

OS总是将fd=0,1,2的文件,认为是标准输入流,标准输出流,标准错误流文件,因此如果我们将fa=1指向的文件改为其它文件,就可以完成输出重定向。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TO66qrxa-1666710207250)(./%E6%96%87%E4%BB%B6%E6%8F%8F%E8%BF%B0%E7%AC%A6.assets/image-20221025192109016.png)]‘

追加重定向

在打开文件时,通过添加O_APPEND即可完成追加重定向。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eIKbUwFp-1666710207251)(./%E6%96%87%E4%BB%B6%E6%8F%8F%E8%BF%B0%E7%AC%A6.assets/image-20221025192119911-1666696880986-1.png)]

输入重定向

将fd=0的指向文件修改就可以完成输入重定向

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QYwus11w-1666710207253)(./%E6%96%87%E4%BB%B6%E6%8F%8F%E8%BF%B0%E7%AC%A6.assets/image-20221025192139528-1666696900441-3.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Nb0D8RiH-1666710207254)(./%E6%96%87%E4%BB%B6%E6%8F%8F%E8%BF%B0%E7%AC%A6.assets/image-20221024214929556-1666619370504-7.png)]

dup

 #include <unistd.h>
int dup(int oldfd);
int dup2(int oldfd, int newfd);
#define _GNU_SOURCE             /* See feature_test_macros(7) */
#include <fcntl.h>              /* Obtain O_* constant definitions */
#include <unistd.h>
int dup3(int oldfd, int newfd, int flags);
  1. 文件结构体的销毁使用的是“引用计数”方式,销毁也是进程消失后OS进行的销毁
  2. 我们通过关闭fd为012的指针数组,利用文件描述符的匹配规则,就可以完成重定向操作,但是这很麻烦,可以通过一个系统接口函数dep相关接口,进行操作
  3. 主使用dup2

dup2

 int dup2(int oldfd, int newfd);
 //dup2() makes newfd be the copy of oldfd, closing newfd first if necessary, but note the following:
  1. dup2的修改逻辑是将oldfd拷贝到newfd,与正常逻辑相反
  2. 因此如果想完成重定向,需要fd(x,0/1/2);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cxyA8VnF-1666710207255)(./%E6%96%87%E4%BB%B6%E6%8F%8F%E8%BF%B0%E7%AC%A6.assets/image-20221024231514160-1666624515191-11.png)]

标准输出和标准错误的区别

  1. 2者都会打开屏幕这个标准输出文件,但是2者的文件描述符是不一样的
  2. 可以通过 2>&1 ,将标准错误重定向到一个文件中

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SMsTzXlR-1666710207256)(./%E6%96%87%E4%BB%B6%E6%8F%8F%E8%BF%B0%E7%AC%A6.assets/image-20221025193907238-1666697948095-5.png)]

缓冲区

  1. 设置缓冲区存在目的:减少IO操作,提高整体的效能
  2. 我们所说的缓冲区指的是语言级别的缓冲区、

    1. 因为和输出相关的函数(printf,fprintf....)都会调用系统接口write,但是write是不受刷新策略的影响,所以这个缓冲区和OS是无关的,一定是在输出函数内部,也就是和语言强相关。这也就是为什么有些时候数据没有成功从缓冲区中刷新出来的原因。
    2. 这其实是文件结构体中的一个类似容器的成员。
  3. 当进程退出的时候,会刷新FILE内部的数据到OS中。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EWYMl3oG-1666710207257)(./%E6%96%87%E4%BB%B6%E6%8F%8F%E8%BF%B0%E7%AC%A6.assets/image-20221025211153940-1666703514960-11.png)]

  4. 如果在刷新缓冲区前,我们关闭了输出文件,那么数据是无法刷新到OS的,也就是无法保存到文件中

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T3WpdKOZ-1666710207259)(./%E6%96%87%E4%BB%B6%E6%8F%8F%E8%BF%B0%E7%AC%A6.assets/image-20221025211208533-1666703529376-13.png)]

子进程与缓冲区

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NgjHWnyM-1666710207262)(./%E6%96%87%E4%BB%B6%E6%8F%8F%E8%BF%B0%E7%AC%A6.assets/image-20221025222424219-1666707865414-15.png)]

进程替换与缓冲区

进程替换替换的是代码和数据,因此原来进程所创建的内核数据结构是不变的:文件描述符指针数组也不变。即如果新的程序需要打开文件,会在原有的内核数据结构上补充内容。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vFUQNkt5-1666710207263)(./%E6%96%87%E4%BB%B6%E6%8F%8F%E8%BF%B0%E7%AC%A6.assets/image-20221025224606006.png)]

相关文章
|
存储 文件存储 数据安全/隐私保护
文件管理介绍
文件管理是操作系统中的一个重要组成部分,它负责管理计算机系统中的文件和文件系统的组织结构。文件是存储在存储介质上的一组相关数据,可以是文本文件、图像文件、音频文件、视频文件等。文件管理的目标是有效地组织、存储、检索和保护文件,提供方便的文件操作和共享功能。 文件管理的主要功能包括文件存储和文件操作两个方面: 1. 文件存储: - 文件组织结构:文件系统采用一种层次化的组织结构,常见的有层次目录结构、索引结构和扁平文件结构等。层次目录结构是最常见的文件组织方式,通过目录和子目录的层次关系来组织文件。索引结构是利用索引表来存储文件的位置和属性信息,可以提高文件的访问速度。扁平文件结构是将
174 1
|
存储 安全 算法
文件管理
一、文件管理 文件管理是操作系统中的一个重要功能,它负责管理计算机系统中的文件和文件系统。文件是计算机中存储数据的基本单位,文件管理涉及文件的创建、读取、写入、删除、修改和组织等操作。 文件管理的主要任务包括: 1. 文件创建和删除:文件管理负责创建新文件和删除不再需要的文件。在文件创建过程中,需要分配文件的唯一标识符和存储空间,并记录文件的属性信息。在文件删除过程中,需要释放文件占用的存储空间,并更新文件系统的相关信息。 2. 文件读取和写入:文件管理负责实现对文件的读取和写入操作。读取文件时,文件管理根据文件的标识符和位置信息,从存储介质中读取相应的数据,并将数据传递给请求的进程。写入文件
94 0
|
8月前
|
存储 缓存 监控
Linux内存和硬盘空间管理技巧
了解Linux内存和硬盘管理技巧,提升系统性能和稳定性。使用`free`, `top`, `vmstat`监控内存,通过`sync`, `echo 1 &gt; /proc/sys/vm/drop_caches`清理缓存。利用Swap分区释放内存。借助`df`, `du`检查硬盘空间,清理无用文件,使用`clean-old`, `gzip`, `tar`压缩归档。查找大文件用`find`和`du`,确保
103 0
|
存储 算法
内存的管理(2)
内存的管理
57 0
|
调度
内存的管理(1)
内存的管理
61 0
|
存储 安全 Unix
第5章 文件管理
第5章 文件管理
264 0
|
存储
六、文件管理
六、文件管理
165 0
六、文件管理
|
算法 存储
页式管理,段式管理,段页式内存管理
一 页式管理 1 页式管理的基本原理将各进程的虚拟空间划分成若干个长度相等的页(page),页式管理把内存空间按页的大小划分成片或者页面(page frame),然后把页式虚拟地址与内存地址建立一一对应页表,并用相应的硬件地址变换机构,来解决离散地址变换问题。
2829 0