File-OS(简单文件系统的实现)

来源:互联网 发布:仙剑传奇网站源码 编辑:程序博客网 时间:2024/05/29 19:03

前言

期末的OS的大作业,写了一个简单的文件管理系统,写了5天左右(实际整个项目历经一个月(大部分时间在挂机),花了不少时间来构思,设计系统的架构。。。。),写的比较辛苦,既然花了这么久的时间,那就拿出来分享下,希望各位指点指正。。

项目github地址

https://github.com/qq1367212627/File-OS

简单的介绍

基本的功能是在磁盘上(D:/VitualDisk/)开辟一个虚拟磁盘,实现对文件的基本操作,下面是具体的系统介绍。

设计原理&目标

File-OS (系统目标)

File Operating System #简单文件系统的实现 1).目的 通过具体的文件存储空间的管理及文件的物理结构、目录结构和文件操作的实现, 加深对文件系统内部功能和实现过程的理解。

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

(2)文件存储空间的分配可采用显示链接分配或者其他的办法。

(3)空闲空间的管理可选择位示图或其他的办法。如果采用位示图来管理文件存储空间,并采用显式链接分配方式, 那么可以将位示图合并到FAT中。

(4)文件目录结构采用多级目录结构。为了简单起见,可以不使用索引结点,其中的每个目录项应包含文件名、 物理地址、长度等信息,还可以通过目录项实现对文件的读写保护。

(5)要求提供以下有关操作:

●format:对文件存储器进行格式化,即按照文件系统 的结构对虚拟磁盘空间进行布局, 并在其上创建根目录以及用于管理文件存储空间等的数据结构。
mkdir:用于创建子目录 rmdir:用于删除子目录 ls:用于显示目录 cd:用于更改当前目录 create:用于创建文件 ●open:用于打开文件 ●close:用于关闭文件 ●write:用于写文件 ●read:用于读文件 rm:用于删除文件

文件系统的设计思路&原理

设计基本的系统类结构思路

下图是简单文件系统的类的继承关系及:

这里写图片描述

文件类(File),文件夹类(Folder)继承自文件控制块FCB类。
访问控制类(Access)用来描述文件夹及文件的访问权限,文件类型(FileType)用来描述文件类型,以区分文件和文件夹。
磁盘管理类(DiskMannger)用来实现与用户的交互与逻辑调用。
文件分配表(FAT)用来存储磁盘块分配占用情况。

文件系统的数据结构

文件夹及文件关系使用树的数据结构保存他们之间的层级包含关系。

文件分配表(FAT)用来存储磁盘块分配占用情况。以下是FAT表的设计思路。
使用2个栈维护盘块索引号,分别维护空的盘块和已占用的盘块。
这里写图片描述

每个文件维护一张索引表,记录文件存储的盘块号
这里写图片描述

定义类方法声明&相应的数据结构

Access类:用来描述文件及文件夹的访问权限。
这里写图片描述

FileType类:描述文件类型
这里写图片描述

FCB类:描述一个文件的基本属性
这里写图片描述

File类:文件类

这里写图片描述

Folder类:文件夹类
这里写图片描述

FAT类:文件分配表(FAT)用来存储磁盘块分配占用情况

这里写图片描述

DiskMannger:磁盘管理类,用来实现与用户的交互与逻辑调用。

这里写图片描述

代码

主函数

main.cpp

#include <windows.h> #include "File.h"#include "DiskMannger.h"using namespace std;int main(){    DiskMannger();    return 0;}

文件控制块(FCB)

FCB.H

#pragma once#include<string>#include "FileType.h"#include "Access.h"#include "FAT.h"#include <time.h>const int N  = 4096;using namespace std;class FCB {public:    string name;//文件名:    文件名.扩展名    int nodeId;//文件标识:操作系统管理文件的唯一标识。    FileType type;//文件类型:由扩展名给出。    string path;//文件位置:文件所存放设备的具体位置。    int size;//文件大小:以字节或块为单位的文件长度。    Access access;//文件的保护方式:通常有读、写、执行等。    string modifyDate;// 文件的创建或修改日期。    FCB *index[N];//索引表    FCB *father;//父节点    FCB();    ~FCB();    string getTime();//获取系统时间};

FCB.CPP

#pragma once#include "FCB.H"FCB::FCB() {    this->access = Write;    this->modifyDate = getTime();    this->size = N;}FCB::~FCB(){}string FCB::getTime(){    time_t t = time(0);    char tmp[64];    strftime(tmp, sizeof(tmp), "%Y/%m/%d %X", localtime(&t));    return tmp;}

文件分配表(FAT类)

FAT.H

#pragma once#include<stack>#include<algorithm>const static int BLOCK_SIZE = 4096/sizeof(bool);using namespace std;class FAT {public:    stack<int>freeDiskBlock;//空磁盘块栈    stack<int>fullDiskBlock;//占用磁盘块    void init(string  blocks[]);    int  getBlock();    void addBlock(int block, string  blocks[]);//获取一个空的磁盘块};Contact GitHub API Training Shop Blog About

FAT.CPP

#include<cstring>#include "FAT.h"void FAT::init(string blocks[])//初始化磁盘{    for (int i = 0; i < BLOCK_SIZE; i++) {        this->freeDiskBlock.push(i);        blocks[i].clear();    }}int FAT::getBlock()//获取空磁盘{    if (this->freeDiskBlock.size() > 0) {        int blockId = this->freeDiskBlock.top();        this->freeDiskBlock.pop();        this->fullDiskBlock.push(blockId);        return blockId;    }    return -1;}void FAT::addBlock(int block, string  blocks[])//回收磁盘块{    this->freeDiskBlock.push(block);    blocks[block].clear();}

文件类

File.h

#pragma once#include "FCB.H"#include<string>class File:public FCB{public:    //构造函数    File();    File(string _name, FileType _type, FAT & fat);    //析构函数    ~File();    //序列化    void Serialization();    //反序列化    void Deserialization();    bool addContent(const char * content, string  blocks[], FAT & fat);    //文件索引    int index[N];    //上一级文件夹    FCB* father;    void release(FAT & fat, string* blocks);    string toString(string blocks[]);    //释放磁盘块};

File.cpp

#include "File.h"File::File() {}File::File(string _name, FileType _type,FAT &fat){    this->name = _name;    this->type = _type;    this->size = 0;    this->index[size] = fat.getBlock();//ΪÎļþ·ÖÅä¿Õ¼ä}File::~File(){}void File::Serialization(){}void File::Deserialization(){}bool File::addContent(const char * content,string blocks[],FAT &fat){    int len = strlen(content);    for (int i = 0; i < len; i++) {        if (blocks[index[size]].length()<=N) {            blocks[index[size]] += content[i];        }        else {            index[++size] = fat.getBlock();            blocks[index[size]] += content[i];        }    }    this->modifyDate = this->getTime();    return false;}void File::release(FAT & fat, string * blocks){    for (int i = 0;i<this->size;i++) {        fat.addBlock(index[i],blocks);    }}string File::toString(string blocks[]){    string s;    for (int i = 0; i <= this->size; i++) {        s += blocks[index[i]];    }    return s;}

文件夹类

Folder.h

#pragma once#include "FCB.h"#include "File.h"#include<vector>#include<string>class Folder:public FCB{public:    vector<FCB * >child;    void addChild(FCB* file);    Folder(string _name, FileType _type);    bool count(FCB *file);    FCB* find(FCB *file);    bool erase(FCB* file);    int size();private:    int childSize;};

Folder.cpp

#pragma once#include "Folder.h"void Folder::addChild(FCB * file){    this->child.push_back(file);}Folder::Folder(string _name, FileType _type){    this->name = _name;    this->type = _type;}bool Folder::count(FCB * file){    int size = child.size();    for (int i = 0; i < size; i++) {        if (child[i]->type == file->type&&child[i]->name == file->name) {            return true;        }    }    return false;}FCB* Folder::find(FCB * file){    int size = child.size();    for (int i = 0; i < size; i++) {        if (child[i]->type == file->type&&child[i]->name == file->name) {            return child[i];        }    }    return NULL;}bool Folder::erase(FCB * file){    int size = child.size();    vector<FCB*>::iterator  it;    for (it = child.begin();it!=child.end();it++) {        if ((*it)->type == file->type&&(*it)->name == file->name) {            child.erase(it);            return true;        }    }    return false;}int Folder::size(){    return child.size();}

磁盘管理器类

DiskMannger.h

#pragma once#include "Folder.h"class DiskMannger{public:    void DiskWrite(File * file);    bool DiskMkdir(string dirName);//创建磁盘文件夹    bool DiskRmdir(string dirName);//删除磁盘文件夹    bool DiskCkdir(string dirName);    void DiskRmdir(Folder * f);    //检查磁盘是否存在文件夹    DiskMannger();//磁盘构造函数    ~DiskMannger();    //磁盘类析构函数    void format(string * blocks);//: 对文件存储器进行格式化。    void Mkdir();    void Rmdir();    void ls(); //: 用于显示目录    void cd(); //: 用于更改当前目录    void create();//: 用于创建文件    void open(); //: 用于打开文件    void close(); //: 用于关闭文件    void write(const char * s, File * file);//: 用于写文件    void read(const char * s);//: 用于读文件    void rm(); //: 用于删除文件private:    Folder *root;};

DiskMannger.cpp

#include <windows.h> #include<stack>#include<iostream>#include<iomanip>#include<queue>#include <fstream>  #include<direct.h>  #include<io.h> #include "DiskMannger.h"#include "Folder.h"#include "FileType.h"#include "Access.h"#include "FAT.h"const string ACCESS[] = { "只读","可修改","可执行" };const string rootPath = "D:/VitualDisk/";queue<FCB*> persistQueue;//持久化队列FAT fat;string blocks[N];ofstream *out = NULL;ifstream *in = NULL;using namespace std;void DiskMannger::DiskWrite(File * file){    //文件输出流    printf("%s\n", file->path.c_str());    //freopen(file->name.c_str(), "w", stdout);    out = new ofstream(file->path.c_str());    if (out->is_open())    {        out->close();    }    //cout << "hello world" << endl;   // fclose(stdout);//关闭文件}bool DiskMannger::DiskMkdir(string dirName){    printf("%s\n",dirName.c_str());    return _mkdir(dirName.c_str()) == 0;}bool DiskMannger::DiskRmdir(string dirName){    return rmdir(dirName.c_str()) == 0;}bool DiskMannger::DiskCkdir(string dirName){    if (_access(dirName.c_str(), 0) == -1)    {        return  _mkdir(dirName.c_str()) == 0;    }    return false;}void DiskMannger::DiskRmdir(Folder *f){    //DFS删除    for (int i = 0; i < f->child.size(); i++) {        if (f->child[i]->type == DOCUMENT) {            printf("%s\n", f->child[i]->path.c_str());            remove(f->child[i]->path.c_str());        }else {            this->DiskRmdir((Folder*)f->child[i]);        }    }    printf("%s\n", f->path.c_str());    this->DiskRmdir(f->path.c_str());}DiskMannger::DiskMannger(){    fat.init(blocks);    root = new Folder(rootPath,FileType::FOLDER);    root->path = rootPath;    this->DiskMkdir(rootPath);    //设置磁盘根为目录    //设置根节点的父节点为自身    root->father = root;    cout << "欢迎!!-----------您可输入help获得帮助------------" << endl<< "\n[root@localhost "+rootPath+"]# ";    string opear,cmd;    while (cin >> cmd)     {         if (cmd == "format") {            this->format(blocks);        }        else if (cmd == "mkdir") {            this->Mkdir();        }        else if (cmd == "rmdir") {            this->Rmdir();        }        else if (cmd == "ls") {            this->ls();        }        else if (cmd == "cd") {            this->cd();        }        else if (cmd == "create") {            this->create();        }        else if (cmd == "open") {            this->open();        }        else if (cmd == "close") {            this->close();        }        else if (cmd == "rm") {            this->rm();        }        else if (cmd == "exit") {            printf("%s\n", "再见!");            break;        }        else if(cmd=="help"){            cout << "\n●format:对文件存储器进行格式化.\n"<<                "●mkdir:用于创建子目录\n" <<                "●rmdir : 用于删除子目录\n" <<                "●ls : 用于显示目录\n" <<                "●cd : 用于更改当前目录\n" <<                "●create : 用于创建文件\n" <<                "●open : 用于打开文件\n" <<                "●close : 用于关闭文件\n" <<                "●write : 用于写文件\n" <<                "●read : 用于读文件\n" <<                "●rm : 用于删除文件\n" <<                "●exit : 退出系统\n"                <<endl;        }        else {            cout << "输入指令错误,请重新输入!!" << endl;        }        cout << "\n[root@localhost "+this->root->path+" ]# ";    }}DiskMannger::~DiskMannger(){}void DiskMannger::format(string *blocks){    fat.init(blocks);    //回退到根目录    while (root->father != root) {        this->root = (Folder*)(this->root->father);    }    this->DiskRmdir(this->root);    root->child.clear();    printf("%s\n", "磁盘格式化成功!");}void DiskMannger::Mkdir(){    string name;    cin >> name;    Folder *childFile = new Folder(name,FileType::FOLDER);    //设置父节点    childFile->father = (this->root);    childFile->path = this->root->path + name + "/" ;    //判断是否文件重复    if (this->root->count(childFile)) {        //文件重复报错        cout << "创建文件夹失败,文件夹名出现重复" << endl;    }else {        cout << "创建文件夹成功" << endl;        this->DiskMkdir(childFile->path);        this->root->addChild(childFile);    }}void DiskMannger::Rmdir(){    string name;    cin >> name;    Folder *childFile =new Folder(name, FOLDER);    childFile = (Folder*) this->root->find(childFile);    if (this->root->erase(childFile)) {        //文件重复报错        this->DiskRmdir(childFile);        cout << "删除文件夹成功" << endl;    }else {        cout << "无此文件夹 ,删除文件夹失败" << endl;    }}void DiskMannger::ls(){    cout << setw(10) << "访问权限"        << setw(20) <<"文件大小"        << setw(25) << "修改日期"        << setw(20) << "文件名"        << endl;    int size = this->root->size();    for(int i= 0;i<size;i++)    {        cout << setw(10) << ACCESS[this->root->child[i]->access]            << setw(20) << (this->root->child[i]->type != FOLDER ? ((File*)this->root->child[i])->toString(blocks).size() : 4096)            << setw(25)<<this->root->child[i]->modifyDate            << setw(20)<<this->root->child[i]->name            <<endl;    }}void DiskMannger::cd(){    string name;    cin >> name;    if (name == "..") {        this->root = (Folder*)(this->root->father);    }    else {        if (this->root->count(new Folder(name, FOLDER))) {            if (this->root->find(new Folder(name, FOLDER))->type != FOLDER)            {                cout << "无此文件夹" << endl;            }            else            {                root = (Folder*)this->root->find(new Folder(name, FOLDER));            }        }        else {            cout << "无此文件夹 " << endl;        }    }}void DiskMannger::create(){    string name;    cin >> name;    File *childFile =  new File( name, DOCUMENT,fat);    //设置父节点    childFile->father = (this->root);    childFile->path = this->root->path + name;    //判断是否文件重复    if (this->root->count(childFile)) {        //文件重复报错        cout << "创建文件失败,文件名出现重复!!" << endl;    }    else {        cout << "创建文件成功!" << endl;        this->root->addChild(childFile);        this->DiskWrite(childFile);    }}void DiskMannger::open(){    string name,cmd;    cin >> name;    File * file = (File*)this->root->find(new File(name, DOCUMENT,fat));    if (file!=NULL) {        printf("%s\n", "文件读写流打开成功!");        cout << "\n[root@localhost " + this->root->path + " ]# ";        while (cin>>cmd) {            cout << "\n[root@localhost " + this->root->path + " ]# ";            if (cmd == "write") {                this->write(file->path.c_str(), file);            }            else if (cmd == "read") {                this->read(file->path.c_str());            }            else if (cmd == "close") {                this->close();                break;            }        }    }    else {        printf("%s\n", "无法打开文件读写流,无此文件!");    }}void DiskMannger::close(){    if (out == NULL||in==NULL) {        printf("%s\n", "无文件读写流需要关闭!");    }else {        out->close();        in->close();        printf("%s\n", "文件读写流关闭成功!");    }}void DiskMannger::write(const char *s, File* file){    string content;    cin >> content;    if (in != NULL)in->close();    file->addContent(content.c_str(), blocks, fat);//添加内容到文件中    content = file->toString(blocks);    out = new ofstream(s);    if (out->is_open())    {        *out << content;    }    out->close();}void DiskMannger::read(const char *s){    char *content = new char[N];    if (out != NULL)out->close();    in =  new ifstream(s);    if (in->is_open())    {        *in >> content;    }    in->close();    cout << content;}void DiskMannger::rm(){    string name;    cin >> name;    File *childFile = new File(name, DOCUMENT,fat);    if (this->root->count(childFile)) {        //文件重复报错        childFile =(File*) this->root->find(childFile);        remove(childFile->path.c_str());        childFile->release(fat,blocks);        this->root->erase(childFile);        cout << "删除文件成功!" << endl;    }    else {        cout << "无此文件 ,删除文件失败" << endl;    }}

访问控制类(Access)

Access.h

#pragma onceenum Access {    ReadOnly,//只读    Write,  //写    Executable//可执行};

文件类型(FileType)

FileType.h

#pragma onceenum FileType {    FOLDER , //文件夹    DOCUMENT//文件};

以下为主要功能的函数设计思路

DiskMannger();//磁盘构造函数
初始化磁盘类,逻辑调用与用户交互通过此函数实现。设置磁盘的根目录为自身,即设置一个树的root节点

void format(); //: 对文件存储器进行格式化。

格式化磁盘,包括对fat表的初始化,磁盘文件的删除,删除现存的节点关系,结构初始化。

void Mkdir();

判断是否存在同名文件夹,若不存在则添加一个文件夹的节点到这个树的目录结构上,在磁盘对应的文件夹创建一个新的文件夹

void Rmdir();
判断是否存在存在在这个目录中,然后从这个树的目录结构上删除这个文件夹的节点,在磁盘对应的文件夹删除文件夹,

void ls(); //: 用于显示目录

遍历当前的文件夹下的文件及文件夹,通过判断文件还是文件夹来控制显示的颜色,文件夹显示为黄色,而文件显示为白色。

void cd(); //: 用于更改当前目录

先判断是否是 .. 这个目录,若为 .. ,则将当前的指针指向当前节点的父节点,否则在当前的目录先查询是否有这个文件夹,若存在则切换,将指针指向目标地址,否则就输出提示错误信息。

void create();//: 用于创建文件

首先在判断当前的文件夹是否存在有相同的文件名,若已经存在则输出错误提示信息,否则创建一个File节点对象添加到当前的文件夹下,作为当前文件夹的子节点,然后创建一个文件到磁盘上。

void open(); //: 用于打开文件

先判断文件是否存在,若存在则创建ofstream,ifstream对象,打开目标的文件读写数据流,开始准备读写数据。若不存在则输出错误提示。

void close(); //: 用于关闭文件流

判断当前是否有文件流需要关闭,若存在输入输出流,则将其调用close函数关闭,否则输出错误提示信息

void write(const char * s, File * file);//: 用于写文件

用户输入字符,将字符追加到文件中,由ifstream文件流存储到磁盘,将字符追加到文件对象中,由文件对象添加到磁盘块中。

void read(const char * s);//: 用于读文件

读取ofstream流中的文件并输出。

void rm(); //: 用于删除文件

在当前目录查找是否存在文件,若存在则:使用

结尾

以上就是整个系统的设计啦,写的不好希望多多指出来,我会尽快修改,就这样啦~(≧▽≦)/~

原创粉丝点击