实验-简单文件系统的实现

1、实验目的

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

2、实验内容

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

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
#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;
}
作者

Meow Meow Liu

发布于

2020-10-22

更新于

2024-04-23

许可协议

评论