您的位置:首页 > 编程语言

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

2017-05-31 01:03 609 查看

前言

期末的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
;//索引表
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
;
//上一级文件夹
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
;
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
;
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 once
enum Access {
ReadOnly,//只读
Write,  //写
Executable//可执行
};


文件类型(FileType)

FileType.h

#pragma once

enum 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(); //: 用于删除文件


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

结尾

以上就是整个系统的设计啦,写的不好希望多多指出来,我会尽快修改,就这样啦~(≧▽≦)/~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  github 文件系统 磁盘
相关文章推荐