实验 简单文件系统的实现

1、实验目的

通过具体的文件存储空间的管理、文件的物理结构、目录结构和文件操作的实现,加深对文件系统内部功能和实现过程的理解。

2、实验内容

  1. 在内存中开辟一个虚拟磁盘空间作为文件存储器,在上面实现一个简单单用户文件系统。退出时应该将该虚拟文件系统保存到磁盘上,以便下次可以再将它恢复到内存对虚拟磁盘空间中。
  2. 文件存储空间对分配可以采用显式链接分配或者其他的办法。
  3. 空闲空间的管理可以选择位示图或者其他的办法。如果采用位示图来管理文件存储空间,并采用显式链接分配方式,那么可以将位示图合并到FAT中。
  4. 文件目录结构采用多级目录结构。为了简单起见,可以不使用索引结点,其中的每个目录项应包含文件名、物理地址、长度等信息,还可以通过目录项实现对文件对读和写的保护。
  5. 要求提供以下有关的操作:
√format:对文件存储器进行格式化,即按照文件系统对结构对虚拟磁盘空间进行布局,并在其上创建根目录以及用于管理文件存储空间等的数据结构。
√mkdir:用于创建子目录;
√rmdir:用于删除目录;
√ls:用于显示目录;
√cd:用于更改当前目录;
√create:用于创建文件;
√open:用于打开文件;
√close:用于关闭文件;
√write:用于写文件;
√read:用于读文件
√rm:用于删除文件。

代码

#include <iostream>
#include <vector>
#include <iomanip>
#include <fstream>
using std::string;
using std::vector;
using std::cout;
using std::endl;
using std::cin;
using std::ifstream;
using std::ofstream;
using std::ios;
class FCB{
public:
    int first_block;
    string fileName;
    int size;
    int real_size;
    FCB(int first_block0,const string &fileName0, int size0, int real_size0):
        first_block(first_block0),
        fileName(fileName0),
        size(size0),
        real_size(real_size0*4) {
    }
}; //文件控制块
class DirItem { //文件树
    string name;
    vector<FCB*> files; //目录下的文件
    vector<DirItem*> dirs; //目录下的文件夹,树节点
public:
    DirItem(const string& name0):name(name0) {}
    void addFile(int first_block, const string& fileName,int size, int real_size) {
        for (auto i = files.begin(); i != files.end(); i++) {
            if ((*i)->fileName == fileName) {
                cout << "same file name" << endl;
                return;
            }
        }
        files.push_back(new FCB(first_block, fileName, size, real_size));
    }
    void addDir(DirItem* dir) {
        dirs.push_back(dir);
    }
    vector<DirItem*> getDirs() {
        return dirs;
    }
    vector<FCB*> getFiles() {
        return files;
    }
    string getName() {
        return name;
    }
    void del_file(const string& fileName) {
        for (auto i = files.begin(); i != files.end(); i++) {
            if ((*i)->fileName == fileName) {
                files.erase(i);
                break;
            }
        }
    }
    void del_dir(const string& fileName) {
        for (auto i = dirs.begin(); i != dirs.end(); i++) {
            if ((*i)->getName() == fileName) {
                dirs.erase(i);
                break;
            }
        }
    }
    void clear() {
        for (DirItem* item : dirs) {
            delete item;
        }
        for (FCB* item : files) {
            delete item;
        }
        dirs.clear();
        files.clear();
    } //递归删除时用到,删除当前目录下的目录和文件的指针
};

class diskMgr { //磁盘
    vector<int> blocks; //fat表
    int n = 16;
    int block_num = n*n;
    int block_size = 4; //每块4B
    int disk_capacity = block_num * block_size; //1M
    vector<vector<int>> bit_map; //0空,1有,位视图
public:
    vector<char> disk;
    diskMgr() {
        disk = vector<char>(disk_capacity, '\0');
        blocks = vector<int>(block_num, -1);
        bit_map = vector<vector<int>>(n, vector<int>(n, 0));
    }
    int getSize(int blockNum) {
        int n = 0;
        while (blockNum != -1) {
            n++;
            blockNum = blocks[blockNum];
        }
        return n;
    } //当前块号开始的文件一个有多少块儿
    int find_empty_block() {
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (bit_map[i][j] == 0) {
                    return n*i+j;
                }
            }
        }
        return -1;
    }//找到一个空闲盘块,从位视图
    void update_bit_map(int x, int notempty) {
        int i = x / n,j = x % n;
        bit_map[i][j] = notempty;
    }//更新位视图
    void del(int blockNum) {
        while (blockNum != -1) {
            for(int i = 0; i < block_size; i++) {
                disk[blockNum * block_size + i] = '\0';
            }
            update_bit_map(blockNum, 0);
            int t = blocks[blockNum];
            blocks[blockNum] = -1;
            blockNum = t;
        }
    } //删除文件
    vector<char> read(int blockNum) {
        vector<char> data;
        while (blockNum != -1) {
            for(int i = 0; i < block_size; i++) {
                data.push_back(disk[blockNum * block_size + i]);
            }
            blockNum = blocks[blockNum];
        }
        return data;
    } //读取文件
    int write(vector<char> data) {
        int first_block = find_empty_block(); //找到初始位置
        if (first_block == -1) return -1;
        int len = int(data.size());
        int blockn = len%block_size == 0 ? len/block_size : len/block_size+1; //一共需要的盘块儿数
        int next_block = first_block;
        int temp = next_block;
        int fix = (block_size - len % block_size) % block_size;

        for (int i = 0; i < fix; ++i) { //数据长度对齐
            data.push_back('*');
        }
        for (int i = 0; i < blockn; i++) { //存数据
            if (temp == -1) {
                break;
            }
            next_block = temp;
            for (int j = 0; j < block_size; j++) {
                disk[next_block*block_size+j] = data[i*block_size+j];
            }
            update_bit_map(next_block, 1);
            temp = find_empty_block();
            blocks[next_block] = temp;

        }
        blocks[next_block] = -1;
        return first_block;
    }

};
#define chart_head std::left << std::setw(len+1) << std::setfill('-') << ""
#define chart_cell "|" << std::left << std::setw(len) << std::setfill(' ')
class fileMgr {
    DirItem * root; //根节点
    diskMgr dm;//磁盘管理器
    DirItem * cur; //当前命令行执的工作目录
    string cur_path; //工作命令
    DirItem* addmdir(DirItem * node, string name) {
        DirItem* newNode = new DirItem(name);
        node->addDir(newNode);
        return newNode;
    }
public:

    fileMgr() {
        root = new DirItem("/");
        DirItem * temp = addmdir(addmdir(root, "apps"), "tencent");
        addmdir(temp, "qq");
        addmdir(temp, "qqgame");
        addmdir(temp, "qqmusic");
        temp = addmdir(root, "docs");
        addmdir(temp, "words");
        addmdir(temp, "ppts");
        addmdir(temp, "excels");

        root->addDir(new DirItem("pics"));
        root->addDir(new DirItem("musics"));
        cur = root;
        cur_path = "/";
        cout_hint();
    } //初始化一些文件夹
    void ls() {
        int len = 20;
        cout
            << chart_head << chart_head << chart_head << chart_head << endl
            << chart_cell << "file/dir name"
            << chart_cell << "type"
            << chart_cell << "size"
            << chart_cell << "real size" << "|" << std::endl
            << chart_head << chart_head << chart_head << chart_head << endl;
        vector<DirItem*> dirs = cur->getDirs();
        for (auto i = dirs.begin(); i != dirs.end(); i++) {
            cout
                << chart_cell << (*i)->getName()
                << chart_cell << "directory"
                << chart_cell << "--"
                << chart_cell << "--" << "|" << std::endl;
        } 
        vector<FCB*> files = cur->getFiles();
        for (auto i = files.begin(); i != files.end(); i++) {
            cout
                    << chart_cell << (*i)->fileName
                    << chart_cell << "file"
                    << chart_cell << (*i)->size
                    << chart_cell << (*i)->real_size << "|" << std::endl;
        }
        cout
            << chart_head << chart_head << chart_head << chart_head << endl;
        cout_hint();
    }
    void cout_hint() {
        cout << "\n" << cur_path << "> ";
    } //输出命令行提示符
    void cd(string name) {
        if (name == "..") {
            if(cur_path == "/") {
                cout_hint();
            } else {
                if (*cur_path.rbegin() == '/') {
                    cur_path.pop_back();
                }
                cur_path = cur_path.substr(0, cur_path.rfind('/'));
                if (cur_path.length() == 0) {
                    cur_path = "/";
                }
                cur = find_dir_node(cur_path);
                cout_hint();
                return;
            }
        }
        DirItem* node = cur;
        for(DirItem* item : node->getDirs()){
            if (item->getName() == name) {
                cur = item;
                cur_path += name+"/";
                cout_hint();
                return;
            }
        }
        cout << "no such dir";
        cout_hint();
    }
    void cdn(string path) {
        cur = find_dir_node(path);
        if (*path.rbegin() != '/') {
            path.push_back('/');
        }
        if (*path.begin() != '/') {
            path = "/" + path;
        }
        cur_path = path;
        cout_hint();
    }
    DirItem* find_dir_node(string path) {
        if (path[0] == '/') {
            path = path.substr(1, path.length()-1);
        }
        if (*path.rbegin() != '/') {
            path.push_back('/');
        }
        int r = 0;
        DirItem* node = root;
        if (path == "/") return node;
        while (r != -1) {
            r = path.find('/');
            if (r != -1) {
                string dir = path.substr(0, r);
                bool find = false;
                for(DirItem* item : node->getDirs()){
                    if (item->getName() == dir) {
                        node = item;
                        find = true;
                        break;
                    }
                }
                if (!find) {
                    return nullptr;
                }
                path = path.substr(r+1, path.length() - r - 1);
            } else {
                break;
            }
        }
        return node;
    }
    void create_file(const string& fileName, const vector<char>& data) {
        DirItem *node = cur;
        if (node != nullptr) {
            int fb = dm.write(data);
            if(fb == -1) {
                cout << "no enough disk storage";
                cout_hint();
            }
            int size = dm.getSize(fb);
            node->addFile(fb, fileName, data.size(), size);
        }
        cout_hint();
    }
    void create_file(string path, const string& fileName, const vector<char>& data) {
        DirItem *node = find_dir_node(path);
        if (node != nullptr) {
            int fb = dm.write(data);
            int size = dm.getSize(fb);
            node->addFile(fb, fileName, data.size(), size);
        }
    }
    void create_dir(const string& dirName) {
        if (cur != nullptr) {
            cur->addDir(new DirItem(dirName));
        }
        cout_hint();
    }
    void create_dir(string path, const string& dirName) {
        DirItem * node = find_dir_node(path);
        if (node != nullptr) {
            node->addDir(new DirItem(dirName));
        }
    }
    void del_dir(DirItem* node) {
        if (node != nullptr) {
            for(FCB* fcb : node->getFiles()) {
                dm.del(fcb->first_block);
                node->del_file(fcb->fileName);
            }
            for(auto i : node->getDirs()) {
                del_dir(i);
            }
            node->clear();
        }
    }
    void del_dir(const string& fileName) {
        if (cur != nullptr) {
            for (auto i : cur->getDirs()) {
                if(i->getName() == fileName) {
                    del_dir(i);
                    cur->del_dir(i->getName());
                    cout_hint();
                    return;
                }
            }
        }
        cout << "no such directory";
        cout_hint();
    }
    void del_file(const string& fileName) {
        DirItem*node = cur;
        if (node != nullptr) {
            for(FCB* fcb : node->getFiles()) {
                if (fcb->fileName == fileName) {
                    dm.del(fcb->first_block);
                    node->del_file(fileName);
                    cout_hint();
                    return;
                }
            }
        }
    }
    void del_file(string path, const string& fileName) {
        DirItem*node = find_dir_node(path);
        if (node != nullptr) {
            for(FCB* fcb : node->getFiles()) {
                if (fcb->fileName == fileName) {
                    dm.del(fcb->first_block);
                    node->del_file(fileName);
                    return;
                }
            }
        }
    }
    void show(const vector<char>& v) {
        for (char i : v) {
            cout << i;
        }
    }
    void read(const string& fileName) {
        if (cur != nullptr) {
            for(FCB* fcb : cur->getFiles()) {
                if (fcb->fileName == fileName) {
                    vector<char> data = dm.read(fcb->first_block);
                    show(data);
                    cout_hint();
                    return;
                }
            }
        }
        cout << "file not found";
        cout_hint();
    }
    vector<char> read(string path, const string& fileName) {
        DirItem*node = find_dir_node(path);
        if (node != nullptr) {
            for(FCB* fcb : node->getFiles()) {
                if (fcb->fileName == fileName) {
                    return dm.read(fcb->first_block);
                }
            }
        }
        return {};
    }


};
int main() {


    fileMgr fm;
    /*ifstream Myfile2;
    Myfile2.open("file_sys.disk",ios::binary);
    //二进制打开,缺省为文本,ios::out,ios::in,文本输入输出用<<,>>
    Myfile2.read((char *)&fm,sizeof(fileMgr));
    Myfile2.close();*/
    string ins, para;
    while(cin >> ins) {
        if(ins == "ls") {
            fm.ls();
        } else if(ins == "cd") {
            cin >> para;
            fm.cd(para);
        } else if (ins == "read") {
            cin >> para;
            fm.read(para);
        }  else if (ins == "mkdir") {
            cin >> para;
            fm.create_dir(para);
        } else if (ins == "rmdir") {
            cin >> para;
            fm.del_dir(para);
        } else if (ins == "mkfile") {
            cin >> para;
            string c = "";
            cout << "contents:\n";
            string data;
            while(c != "#") {
                data += c;
                std::getline(cin, c);
                data += '\n';
            }
            int k = 0;
            while (data[k] == '\n') k++;
            data = data.substr(k, data.length()-k);
            vector<char> vdata;
            for(char i : data) {
                vdata.push_back(i);
            }
            fm.create_file(para, vdata);
        } else if (ins == "rmfile") {
            cin >> para;
            fm.del_file(para);
        } else if (ins == "exit" || ins == "quit") {
            break;
        } else if (ins == "cdn") {
            cin >> para;
            fm.cdn(para);
        } else {
            string c;
            std::getline(cin, c);
            ins += " " + c;
            system(ins.c_str());
            cout << "unknown cmd:" << ins << endl;
            fm.cout_hint();
        }
    }


    /*ofstream file;
    file.open("file_sys.disk",ios::binary);
    //缓存的类型是 unsigned char *,需要类型转换
    file.write((char *)&fm,sizeof(fileMgr));  //winServer为类对象
    file.close();*/
    return 0;
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容