文件系统(操作系统实验)

实验内容

(1)在内存中开辟一个虚拟磁盘空间作为文件存储器, 在其上实现一个简单单用户文件系统。 在退出这个文件系统时,应将改虚拟文件系统保存到磁盘上, 以便下次可以将其恢复到内存的虚拟空间中。

(2)要求提供有关操作:format, create, rm, mkdir, rmdir, ls...

format:对文件存储器进行格式化,即按照文件系统对结构对虚拟磁盘空间进行布局,并在其上创建根目录以及用于管理文件存储空间等的数据结构。

mkdir:用于创建子目录;

rmdir:用于删除目录;

ls:用于显示目录;

cd:用于更改当前目录;

create:用于创建文件;

open:用于打开文件;

close:用于关闭文件;

write:用于写文件;

read:用于读文件

rm:用于删除文件

实验原理:

磁盘分区方式:

cpp 复制代码
superblock super; // 超级块

FAT fat;           // FAT 表

bitmap bm;         // 磁盘块的位识图

inodemap im;       // 索引节点的位示图

inode inodes[INODE_SUM]; // 索引节点

inode root;               // 根目录的索引节点

block blocks[BLOCK_SUM]; // 其他索引节点

文件管理系统数据成员:

cpp 复制代码
disk *diskptr;                          // 管理的虚拟磁盘

char *filepath;                         // 虚拟磁盘保存的位置

Buf wdir;                               // 工作目录

Buf wfile;                              // 文件操作缓冲区

Filebuf wprt[10];                       // 读写指针

int cur_blockid = 0;                    // 当前工作目录下的第一个盘块

int cur_inode = -1;                     // 当前工作目录下的索引节点

string workpath;

算法思路:

用FAT表对磁盘块进行链接存储,索引节点和磁盘块均采用位示图的方式进行管理和分配根节点的索引节点号为 -1。

对文件或者目录进行修改删除时,均先切换到对应得目录下再进行操作,执行完毕后再返回原来得工作目录。

程序退出时先将虚拟磁盘写回到目录再退出。

编译执行命令: g++ -o main *.cpp && ./main

效果展示

列出当前目录项得文件和文件夹

查看文件内容

创建文件夹

删除文件夹

创建文件,并读写文件

程序退出时保存原来得磁盘情况

保存的磁盘文件 16进制展示

超级块和部分FAT表

部分根目录:

保存的部分文件内容

保存的磁盘文件大小:

部分源码

data.hpp

cpp 复制代码
#pragma once
#define BLOCK_SIZE 512      // 磁盘块大小 512 B
#define ENTRIES_PER_BLOCK 4 // 每个磁盘块最多 4 个目录项
#define BLOCK_SUM 2048      // 磁盘块数
#define INODE_SUM 2048      // 索引节点数
#define DIRSTY 0            // 目录
#define FILESTY 1           // 普通文件
#define READ 1              // 读权限
#define WRITE 2             // 写权限

disk.hpp

cpp 复制代码
#pragma once
#include "data.hpp"

class superblock
{
public:
    int block_sum; // 盘块的数量
    int inode_sum; // 索引节点的数量
    superblock();
};

class FAT
{
public:
    int next[BLOCK_SUM]; // 链表法
    FAT();
};

class bitmap
{
public:
    char map[BLOCK_SUM / 8]; // 位示图
    bool empty(int no);      // 判断磁盘块是否分配
    void set(int);           // 将磁盘块置为已分配
    void free(int);          // 回收磁盘块
    bitmap();                // 初始化,全部为未分配
    int get();               // 申请一个磁盘块,成功则返回磁盘块号,否则返回 -1
};

class inodemap
{
public:
    char map[INODE_SUM / 8];
    bool empty(int no); // 返回当前节点是否为空
    void set(int);
    void free(int);
    inodemap(); // 初始化位示图
    int get();
};

class inode
{
public:
    int firstblock; // 第一个盘块号
    int type;       // 文件类型
};

class entry
{
public:
    bool flag;      // 目录项是否有效
    char name[123]; // 文件名
    int node;       // 索引节点号
    entry();
};

union block // 磁盘块,有两种组织形式,普通文件目录的形式
{
public:
    char data[BLOCK_SIZE];
    entry entries[ENTRIES_PER_BLOCK];
    block();
};

class disk
{
public:
    superblock super;
    FAT fat;
    bitmap bm;
    inodemap im;
    inode inodes[INODE_SUM];
    inode root;
    block blocks[BLOCK_SUM];
    disk();
};

FS.hpp

cpp 复制代码
#pragma once
#include <string>
#include "disk.hpp"
using std::string;

union Buf // 缓存区,主要用于将目录、文件放到缓冲区处理
{
    entry entries[4096];
    char data[524288];
    block blocks[512];
    Buf();
};

class Filebuf // 读文件工作区,保存已经打开的文件及权限
{
public:
    bool flag = false;
    inode fnode;
    char mod = 0;
    char name[123];
    int fafblock; // 父目录的第一个盘块
};

class FS
{
    disk *diskptr;                          // 管理的虚拟磁盘
    char *filepath;                         // 虚拟磁盘保存的位置
    Buf wdir;                               // 工作目录
    Buf wfile;                              // 文件操作缓冲区
    Filebuf wprt[10];                       // 读写指针
    int cur_blockid = 0;                    // 当前工作目录下的第一个盘块
    int cur_inode = -1;                     // 当前工作目录下的索引节点
    void loadbuf(int firstblock, Buf &buf); // 载入缓冲区,可以执行工作目录和文件操作缓冲区的加载
    void writebackdir(int firstblock);      // 写回目录,常常在切换工作目录时写回
    void writebackfile(int firstblock);     // 写回文件,完成写文件后写回
    void delfile(int firstblock);           // 删除文件,包括目录和普通文件

    /*------------------ 原子操作(只允许在当前目录下操作) --------------------------------------*/
    int cd(const char *);      // 切换目录,原子操作,返回 1 表示没有该目录
    void create(const char *); // 创建文件
    void rmdir(const char *);  // 删除文件
    void mkdir(const char *);  // 创建目录
    void ls();                 // 列出当前目录下的文件和文件夹

    string getfolerpath(string);
    string getfilename(string);

public:
    string workpath;
    FS(char *file); // 对磁盘格式化,或导入已有的磁盘文件
    ~FS();          // 写回磁盘并保存

    /*------------------ 原子操作(只允许在当前目录下操作) --------------------------------------*/
    int open(const char *, char mod); // 返回一个 wptr,只能打开当前目录的文件
    void write(int, const char *);    // 写文件,第一个参数为写指针,第二个参数为写的内容
    void close(int);                  // 关闭文件
    void read(int);                   // 读文件,参数为读指针
    void rm(int);                     // 删除文件,需要先打开文件才能删除

    /*--------------------- 允许任何在路径下操作(只有changedir 会改变工作路径)------------------------------*/
    int changedir(const char *);                // 切换工作目录
    void createfile(const char *);              // 创建文件,参数为文件路径
    void removedir(const char *);               // 删除文件夹,参数为文件夹路径
    void list(const char *);                    // 列出指定目录下的文件和文件夹
    void makedir(const char *);                 // 创建文件夹,参数为文件夹路径
    int openfile(const char *, char);           // 打开指定文件,第二个参数为读写权限,返回读写指针
    void writefile(const char *, const char *); // 写文件,第一个参数为文件路径,第二个为写入内容
    void readfile(const char *);                // 读文件
    void removefile(const char *);              // 删除文件
};

main.cpp

cpp 复制代码
#include <iostream>
#include <string>
#include "FS.hpp"
using namespace std;

char file[] = "./FileSys";
FS fs(file);

int main()
{
    cout << "/>";
    string op;
    string contxt;
    string par;
    int wptr;
    while (cin >> op)
    {
        if (op == "ls")
        {
            char a = getchar();
            if (a == '\n')
            {
                char path[] = ".";
                fs.list(path);
            }
            else
            {
                cin >> par;
                fs.list(par.c_str());
            }
        }
        if (op == "cd")
        {
            cin >> par;
            fs.changedir(par.c_str());
        }
        if (op == "touch")
        {
            cin >> par;
            fs.createfile(par.c_str());
        }
        if (op == "mkdir")
        {
            cin >> par;
            fs.makedir(par.c_str());
        }
        if (op == "rmdir")
        {
            cin >> par;
            fs.removedir(par.c_str());
        }
        if (op == "open")
        {
            cin >> par;
            wptr = fs.openfile(par.c_str(), READ | WRITE);
        }
        if (op == "write")
        {
            cin >> par;
            char line[524288];
            contxt = "";
            cin.get();
            cin.getline(line, 524288, '\n');
            cin.clear();
            while (string(line) != "EOF")
            {
                contxt += string(line) + '\n';
                cin.getline(line, 1024, '\n');
                cin.clear();
            }
            fs.writefile(par.c_str(), contxt.c_str());
        }
        if (op == "cat")
        {
            cin >> par;
            fs.readfile(par.c_str());
        }
        if (op == "rm")
        {
            cin >> par;
            fs.removefile(par.c_str());
        }
        if (op == "quit")
            break;
        if (op == "close")
        {
            fs.close(wptr);
        }
        cout << fs.workpath << ">";
    }
}

doc.txt(转载自China Daily)

cpp 复制代码
Precipitation on Tibetan Plateau underestimated
By YAN DONGJIE | China Daily | Updated: 2024-06-07 09:17
Precipitation across the Tibetan Plateau, which is known as Asia's water tower, has been significantly underestimated, Chinese researchers said in a paper published in the Proceedings of the National Academy of Sciences late last month.
The researchers, from the Chinese Academy of Sciences' Institute of Tibetan Plateau Research, said the underestimation is caused by the measuring instruments used and the method of calculation, and called for a "redesigned precipitation observation strategy" to remedy it.
A substantial proportion of precipitation over the plateau falls as snow, often accompanied by strong winds.
The researchers said ground-based instrument monitoring is widely regarded as the primary and most reliable technique for acquiring precipitation data, but traditional ground-level precipitation gauges have a limited cross-section in the collection cylinder and a sealed bottom.
"This design results in the formation of upward supporting airflow under windy conditions, which in turn prevents raindrops or snowflakes from entering the gauge cylinder. Consequently, this leads to an underestimation of precipitation in this region," said Miao Chiyuan from Beijing Normal University, the first author of the study.
Miao said the instrument measurement error caused by strong winds is the primary factor affecting the accuracy of precipitation measurements in high-altitude regions, with errors under extreme weather conditions potentially exceeding 100 percent.
Apart from the equipment, variations in altitude can cause mistakes in the data collected. Weather stations in the region are often placed in valleys or lower areas for convenience, which means they miss out on precipitation that occurs at higher elevations. Additionally, the limited number of stations and their uneven distribution can make the data even less accurate, according to the study.
The Tibetan Plateau, home to more than 100,000 square kilometers of glaciers and 1 million sq km of frozen soil, serves as the source of 10 major Asian river systems flowing into 10 countries, and supports the lives of about 2 billion people.
"In the context of accelerated warming, precipitation across the Tibetan Plateau plays a critical role in water cycles. Accordingly, obtaining reliable precipitation information is a prerequisite for water cycle analysis, future climate projections, and water-related disaster risk assessments," said the institute's Li Xin, the corresponding author of the research.
EOF

file.txt

cpp 复制代码
Desktop
Documents
Downloads
Music
Pictures
Public
Templates
Videos
snap
Desktop/lab1
Desktop/lab2
Desktop/lab3
Desktop/lab4
Desktop/lab5
snap/firefox
snap/firefox/3836
snap/firefox/4336
snap/firefox/common
snap/snapd-desktop-integration
snap/snapd-desktop-integration/83
snap/snapd-desktop-integration/common

存储大文件存在一点问题,自行修改

相关推荐
萨格拉斯救世主35 分钟前
戴尔R930服务器增加 Intel X710-DA2双万兆光口含模块
运维·服务器
无所谓จุ๊บ37 分钟前
树莓派开发相关知识十 -小试服务器
服务器·网络·树莓派
Jtti38 分钟前
Windows系统服务器怎么设置远程连接?详细步骤
运维·服务器·windows
TeYiToKu41 分钟前
笔记整理—linux驱动开发部分(9)framebuffer驱动框架
linux·c语言·arm开发·驱动开发·笔记·嵌入式硬件·arm
dsywws44 分钟前
Linux学习笔记之时间日期和查找和解压缩指令
linux·笔记·学习
yeyuningzi1 小时前
Debian 12环境里部署nginx步骤记录
linux·运维·服务器
上辈子杀猪这辈子学IT1 小时前
【Zookeeper集群搭建】安装zookeeper、zookeeper集群配置、zookeeper启动与关闭、zookeeper的shell命令操作
linux·hadoop·zookeeper·centos·debian
minihuabei1 小时前
linux centos 安装redis
linux·redis·centos
EasyCVR2 小时前
萤石设备视频接入平台EasyCVR多品牌摄像机视频平台海康ehome平台(ISUP)接入EasyCVR不在线如何排查?
运维·服务器·网络·人工智能·ffmpeg·音视频
lldhsds2 小时前
书生大模型实战营第四期-入门岛-1. Linux前置基础
linux