1往踢、實(shí)驗(yàn)?zāi)康?/h1>
通過具體的文件存儲(chǔ)空間的管理、文件的物理結(jié)構(gòu)徘层、目錄結(jié)構(gòu)和文件操作的實(shí)現(xiàn)峻呕,加深對(duì)文件系統(tǒng)內(nèi)部功能和實(shí)現(xiàn)過程的理解。
2趣效、實(shí)驗(yàn)內(nèi)容
- 在內(nèi)存中開辟一個(gè)虛擬磁盤空間作為文件存儲(chǔ)器瘦癌,在上面實(shí)現(xiàn)一個(gè)簡(jiǎn)單單用戶文件系統(tǒng)。退出時(shí)應(yīng)該將該虛擬文件系統(tǒng)保存到磁盤上英支,以便下次可以再將它恢復(fù)到內(nèi)存對(duì)虛擬磁盤空間中佩憾。
- 文件存儲(chǔ)空間對(duì)分配可以采用顯式鏈接分配或者其他的辦法。
- 空閑空間的管理可以選擇位示圖或者其他的辦法干花。如果采用位示圖來管理文件存儲(chǔ)空間妄帘,并采用顯式鏈接分配方式,那么可以將位示圖合并到FAT中池凄。
- 文件目錄結(jié)構(gòu)采用多級(jí)目錄結(jié)構(gòu)抡驼。為了簡(jiǎn)單起見,可以不使用索引結(jié)點(diǎn)肿仑,其中的每個(gè)目錄項(xiàng)應(yīng)包含文件名致盟、物理地址、長度等信息尤慰,還可以通過目錄項(xiàng)實(shí)現(xiàn)對(duì)文件對(duì)讀和寫的保護(hù)馏锡。
- 要求提供以下有關(guān)的操作:
√format:對(duì)文件存儲(chǔ)器進(jìn)行格式化,即按照文件系統(tǒng)對(duì)結(jié)構(gòu)對(duì)虛擬磁盤空間進(jìn)行布局伟端,并在其上創(chuàng)建根目錄以及用于管理文件存儲(chǔ)空間等的數(shù)據(jù)結(jié)構(gòu)杯道。
√mkdir:用于創(chuàng)建子目錄;
√rmdir:用于刪除目錄责蝠;
√ls:用于顯示目錄党巾;
√cd:用于更改當(dāng)前目錄;
√create:用于創(chuàng)建文件霜医;
√open:用于打開文件齿拂;
√close:用于關(guān)閉文件;
√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; //目錄下的文件夾,樹節(jié)點(diǎn)
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();
} //遞歸刪除時(shí)用到,刪除當(dāng)前目錄下的目錄和文件的指針
};
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;
} //當(dāng)前塊號(hào)開始的文件一個(gè)有多少塊兒
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;
}//找到一個(gè)空閑盤塊,從位視圖
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; //一共需要的盤塊兒數(shù)
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) { //數(shù)據(jù)長度對(duì)齊
data.push_back('*');
}
for (int i = 0; i < blockn; i++) { //存數(shù)據(jù)
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; //根節(jié)點(diǎn)
diskMgr dm;//磁盤管理器
DirItem * cur; //當(dāng)前命令行執(zhí)的工作目錄
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);
//二進(jìn)制打開趾代,缺省為文本贯底,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 *,需要類型轉(zhuǎn)換
file.write((char *)&fm,sizeof(fileMgr)); //winServer為類對(duì)象
file.close();*/
return 0;
}