摘要
所有的计算机应用程序都需要存储和检索信息,而长期存储信息有三个基本要求:能够存储大量信息;使用信息的进程终止时,信息仍旧存在;必须能使多个进程并发访问有关信息。在这样的条件下,我们抽象出了一个新的概念——文件来解决这一问题。文件是进程创建的信息逻辑单元。作为一名转专业的学生,本次选择了选题中最难的模拟文件系统,一方面是对这个专业的热爱和想要挑战自己的极限,另一方面是想更深入底层,体会操作系统重要的组成部分即文件系统。
本次课程设计选用的开发环境为Visual Studio 2019,编程语言为C++。之所以使用C++的很大一部分原因在于它的面向对象特性以及指针的运用,作为一门底层语言,C++用来开发操作系统的组件再合适不过。在创建文件与文件之间的关系时采用的数据结构为链表。
编写本次课程设计的代码大致花了两天的时间,第一天整体的代码框架已经编写出来,第二天大部分时间都在调试,最后成果非常显著,测试完全达到了预期的效果。本次实验同时结合了操作系统、面向对象、数据结构等方面的知识,是一个综合型的项目,因此收获颇丰。
代码实现
Filesystem.h
//Filesystem.h
#ifndef FILESYSTEM_H
#define FILESYSTEM_H
#include <iostream>
#include <fstream>
#include <string.h>
#include <string>
#include <iomanip>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
#define SIZE 20 //文件名最大长度
#define Fname "filesys.txt"
extern int tot_disk;
void runFun();
typedef struct MyFile //文件结构体
{
char name[SIZE]; //文件名
int size; //文件大小
string content; //文件内容
string etime; //文件创建时间
string attribute; //文件属性
struct MyFile* nextFile; //指向文件列表中下一个文件
} MyFile;
typedef struct MyDir //目录结构体
{
char name[SIZE]; //目录名字
int size; //目录大小
MyDir* postDir; //后继目录
MyDir* preDir; //前驱目录
MyFile* filePtr; //该目录下的文件链表指针
MyDir* dirPtr; //该目录下的目录链表指针
} MyDir;
class FileSystem //文件系统类
{
private:
char password[SIZE]; //用户密码
char name[SIZE]; //用户名称
int size; //用户所使用空间大小
MyDir* root; //根目录
MyDir* currentDir; //当前目录
public:
FileSystem(char* n, char* c);
~FileSystem();
void init(); //用于重新进入系统时可读入
void save(); //将内存中的信息保存到磁盘
int create(); //用于创建文件
int newDir(); //用于创建目录
int dele_file(MyFile* file); //删除文件
int deleteFile(); //删除文件前的逻辑判断
int dele_dir(MyDir* d); //删除目录
int deleteDir(); //删除目录前的逻辑判断
int read(); //读取文件
int write(); //写入文件
int dir(); //显示当前目录内容
int show_path(MyDir* dir); //显示路径的部分实现
int showPath(); //显示路径
int getSize();//获得用户所在目录大小
int format();//对文件系统进行格式化
MyDir* getCurrentdir(); //获得当前目录
};
#endif // !FILESYSTEM_H
Filesystem.cpp
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <string.h>
#include <string>
#include <iomanip>
#include <ctime>
#include <iomanip>
#include "FileSystem.h"
using namespace std;
extern int tot_disk = 10000; //定义虚拟磁盘空闲空间大小
FileSystem::FileSystem(char* n, char* c) //初始化成员变量,并文件中的内容导入内存
{
size = 0;
currentDir = NULL;
MyDir* root = new MyDir;
strcpy(root->name, n);
strcpy(name, n);
strcpy(password, c);
this->root = root;
currentDir = root;
currentDir->preDir = NULL;
currentDir->dirPtr = NULL;
currentDir->filePtr = NULL;
currentDir->postDir = NULL;
ifstream fcin;
fcin.open(Fname, ios::in);
if (!fcin.is_open())
{
fcin.close();
return;
}
if (fcin.eof())
{
fcin.close();
return;
}
init();
}
FileSystem::~FileSystem()
{
tot_disk += size; //归还虚拟磁盘空间
size = 0; //空间大小归0
MyDir* d = root; //保存根目录地址
MyFile* f = currentDir->filePtr; //获取当前目录首文件地址
while (f != 0)
{ //循环直至目录为空
if (f->nextFile == 0)
{
this->dele_file(f);
f = 0;
break;
}
while (f->nextFile->nextFile != 0) //定位至该目录下的倒二个文件
f = f->nextFile;
this->dele_file(f->nextFile); //删除尾文件逻辑联系
f->nextFile = 0; //置空
f = currentDir->filePtr; //重新获取当前目录首文件地址
}
while (d != 0) { //以同样的方式循环释放目录空间
if (d->postDir == 0) {
this->dele_dir(d);
d = 0;
break;
}
while (d->postDir->postDir != 0)
d = d->postDir;
this->dele_dir(d->postDir);
d->postDir = 0;
d = root;
}
}
void FileSystem::init()
{
ifstream fcin;
fcin.open(Fname, ios::in);
char p_name[SIZE];
int p_size;
string p_content;
string p_etime;
string p_attribute; //将磁盘中的信息读入
while (fcin >> p_name && fcin >> p_size && fcin >> p_etime && fcin >> p_content && fcin >> p_attribute)
{
MyFile* p = NULL;
p = new MyFile;
strcpy(p->name, p_name);
p->size = p_size;
p->content = p_content;
p->etime = p_etime;
p->attribute = p_attribute;
if (currentDir->filePtr == NULL) { //若目录下没有文件
p->nextFile = currentDir->filePtr; //利用头插法将文件插入文件链表
currentDir->filePtr = p;
}
else { //若目录下有文件
p->nextFile = currentDir->filePtr;
//p->size=0;
currentDir->filePtr = p;
MyDir* h = currentDir;
//更改上级目录的大小
while (h != NULL) {
h->size += p->size;
h = h->preDir;
}
}
currentDir->filePtr->size = p_size; //将当前文件大小置0
tot_disk = tot_disk - p->size; //分配磁盘空间
size += p->size;
}
fcin.close();
}
void FileSystem::save()
{
ofstream fout;
fout.open(Fname, ios::out);
MyFile* f = currentDir->filePtr; //获取当前目录首文件地址
if (f != NULL)
{
while (f != NULL)
{
fout << f->name << " " << f->size << " "
<< f->etime << " " << "#" << " " << f->attribute << " " << endl;
f = f->nextFile;
}
}
fout.close();
}
int FileSystem::format()
{ //格式化文件系统
tot_disk += size; //归还虚拟磁盘空间
size = 0; //空间大小归0
MyFile* f = currentDir->filePtr; //获取当前目录首文件地址
while (f->nextFile != 0)
{ //循环直至目录为空
while (f->nextFile->nextFile != 0) //定位至该目录下的倒二个文件
f = f->nextFile;
this->dele_file(f->nextFile); //删除尾文件逻辑联系
f->nextFile = 0; //置空
f = currentDir->filePtr; //重新获取当前目录首文件地址
}
currentDir->filePtr = currentDir->filePtr->nextFile;
cout << "格式化成功!" << endl;
return 1;
}
int FileSystem::newDir()
{ //创建目录
MyDir* p, * h;
p = new MyDir;
cin >> p->name; //读取目录名
p->dirPtr = NULL;
p->size = 0;
p->filePtr = NULL;
p->postDir = NULL;
if (currentDir->dirPtr == NULL)
h = NULL;
else
h = currentDir->dirPtr;
while (h != NULL) { //目录下有子目录,检查是否命名冲突
if (strcmp(h->name, p->name) == 0) {
cout << "目录已存在" << endl;
return 0;
}
h = h->postDir;
}
//利用头插法将目录插入文件系统
p->preDir = currentDir;
p->postDir = currentDir->dirPtr;
currentDir->dirPtr = p;
cout << "创建目录成功!" << endl;
return 1;
}
int FileSystem::create() //创建文件
{
MyFile* p = NULL;
p = new MyFile;
//获取当前的系统时间作为文件的创建时间
SYSTEMTIME sys;
GetLocalTime(&sys);
string mytime = to_string(sys.wYear) + "/" + to_string(sys.wMonth) + "/" + to_string(sys.wDay) + "-"
+ to_string(sys.wHour) + ":" + to_string(sys.wMinute) + ":" + to_string(sys.wSecond);
if (p == 0)
{
cout << "文件创建失败";
return 0;
}
cin >> p->name >> p->attribute; //读入文件名和属性
p->etime = mytime;
if (currentDir->filePtr == NULL) { //若目录下没有文件
p->nextFile = currentDir->filePtr; //利用头插法将文件插入文件链表
currentDir->filePtr = p;
}
else { //若目录下有文件
MyFile* q = new MyFile;
q = currentDir->filePtr;
while (q != NULL) //检测当时目录下是否存在同名文件
{
if (strcmp(p->name, q->name) == 0) {
cout << "文件已存在" << endl;
return 0;
}
q = q->nextFile;
}
p->nextFile = currentDir->filePtr;
//p->size=0;
currentDir->filePtr = p;
MyDir* h = currentDir;
//更改上级目录的大小
while (h != NULL) {
h->size += p->size;
h = h->preDir;
}
}
currentDir->filePtr->size = 0; //将当前文件大小置0
cout << "文件创建成功!" << endl;
tot_disk = tot_disk - p->size; //分配磁盘空间
size += p->size;
return 1;
}
int FileSystem::dele_file(MyFile* f) //删除文件逻辑
{
delete f; //释放文件空间
f = NULL; //置空
return 1;
}
int FileSystem::deleteFile()
{
char temp[SIZE];
cin >> temp;//读入要删除的文件名称
MyFile* f;
MyFile* pre = NULL;
f = currentDir->filePtr; //保存当前文件地址
while (f != NULL) { //遍历目录寻找要删除的文件
if (!strcmp(f->name, temp))
break;
pre = f;
f = f->nextFile;
}
if (f == NULL) {
cout << "未找到此文件" << endl;
return 0;
}
tot_disk += f->size; //归还磁盘空间
MyDir* d = currentDir;
while (d != 0) //修改删除文件后各级目录的大小
{
d->size -= f->size;
d = d->preDir;
}
if (f == currentDir->filePtr)//删除的文件是头结点
currentDir->filePtr = currentDir->filePtr->nextFile;
else //删除的文件非头结点
pre->nextFile = f->nextFile;
size -= f->size; //总空间大小缩减
delete f; //释放该文件
f = NULL;
cout << "文件删除成功!" << endl;
return 1;
}
int FileSystem::dele_dir(MyDir* d) //删除目录逻辑
{
delete d;
d = NULL;
return 1;
}
int FileSystem::deleteDir()
{
char n[SIZE];
MyDir* p, * pre = NULL;
p = root;
p = currentDir->dirPtr;
cin >> n; //读取删除的目录名
//判断是否存在该目录
while (p != NULL) {
if (strcmp(p->name, n) == 0)
{
pre = p; break;
}
p = p->postDir;
}
if (p == NULL) {
cout << "删除失败" << endl;
return 0;
}
tot_disk += p->size; //归还磁盘空间
if (p == currentDir->dirPtr) //若目录是头目录
currentDir->dirPtr = currentDir->dirPtr->postDir;
else
p->preDir->postDir = p->postDir;
pre = currentDir;
while (pre != NULL) //修改删除目录后各级目录空间大小
{
pre->size -= p->size;
pre = pre->preDir;
}
size -= p->size; //修改总空间大小
MyDir* d = p->dirPtr; //获取要删除目录的目录链表
MyFile* f = p->filePtr; //获取要删除目录下的文件
if (f != 0) {
while (p->filePtr->nextFile != NULL)//删除此目录下的文件
{
f = p->filePtr;
while (f->nextFile->nextFile != NULL)//寻找最后一个文件结点
f = f->nextFile;
this->dele_file(f->nextFile); //尾删法
f->nextFile = NULL;
}
if (p->filePtr->nextFile == NULL) {
this->dele_file(p->filePtr);
p->filePtr = NULL;
}
}
if (d != NULL) { //以同样的方式删除目录
while (p->dirPtr->postDir != NULL)//删除此目录下的目录
{
d = p->dirPtr;
while (d->postDir->postDir != NULL)//寻找最后一个文件结点
d = d->postDir;
this->dele_dir(d->postDir);
d->postDir = NULL;
}
if (p->dirPtr->postDir == NULL) {
this->dele_dir(p->dirPtr);
p->dirPtr = NULL;
}
}
delete p, d, f;
cout << "目录删除成功!" << endl;
return 1;
}
int FileSystem::read() //读文件
{
char n[SIZE];
cin >> n;
MyFile* f = currentDir->filePtr;
while (f != 0)
{ //遍历文件链表直到找到目录文件
if (strcmp(f->name, n) == 0)
{
cout << f->content << endl;
return 1;
}
f = f->nextFile;
}
cout << "此文件不存在" << endl;
return 0;
}
int FileSystem::write()
{
char n[SIZE];
string s;
cin >> n;
MyFile* f = currentDir->filePtr;
while (f != 0)
{
if (!strcmp(f->name, n))
{
if (f->attribute == "r")
{
cout << "文件不可写" << endl;
return 0;
}
cin >> s;
f->content = s;
f->size = s.length();
tot_disk -= f->size; //分配磁盘空间
MyDir* d = currentDir;
while (d != 0)//修改各个上级目录的大小
{
d->size += f->size;
d = d->preDir;
}
cout << "文件写入成功!" << endl;
size += f->size;
return 1;
}
f = f->nextFile;
}
cout << "此文件不存在" << endl;
return 0;
}
int FileSystem::show_path(MyDir* d)//显示当前路径
{
cout << root->name << ":$ ";
return 1;
}
int FileSystem::dir() //显示目录下的文件及其信息
{
MyDir* d = currentDir->dirPtr;
MyFile* f = currentDir->filePtr;
if (d == NULL && f == NULL)
{
cout << "当前路径为空" << endl;
return 0;
}
cout << endl;
if (f != NULL)
{
cout << "文件名" << "\t" << "长度" << "\t"
<< "创建时间" << "\t" << "\t" << "物理地址" << "\t" << "属性" << "\t" << endl;
while (f != NULL) {
cout << f->name << "\t" << f->size << "\t"
<< f->etime << "\t" << f << "\t" << f->attribute << "\t" << endl;
f = f->nextFile;
}
}
return 1;
}
int FileSystem::showPath()//显示当前路径
{
show_path(currentDir);
return 1;
}
int FileSystem::getSize()
{
return size;
}
MyDir* FileSystem::getCurrentdir()
{
return currentDir;
}
void help() //输入提示
{
cout << "******************************************************************" << endl;
cout << "* *" << endl;
cout << "* The Use of Instruction *" << endl;
cout << "* *" << endl;
cout << "******************************************************************" << endl;
cout << "* 1.create + filename + attribute 创建文件,并给出属性 *" << endl;
cout << "* r只读,w可读可写 *" << endl;
cout << "* 2.del + filename 删除文件 *" << endl;
cout << "* 3.read + filename 读文件 *" << endl;
cout << "* 4.write + filename 写文件 *" << endl;
cout << "* 5.dir 显示文件 *" << endl;
cout << "* 6.format 格式化文件系统 *" << endl;
cout << "* 6.clear 清屏 *" << endl;
cout << "* 7.exit 注销 *" << endl;
cout << "******************************************************************" << endl
<< endl;
}
int func(char name[30], char pass[30])
{
FileSystem fs(name, pass);
//fs.setUser(name, pass);
while (1) {
system("CLS");
help();
while (1)
{
cout << endl;
string choice;
fs.showPath();
cin >> choice; //获取输入命令并执行对应方法
if (choice == "create")
fs.create();
else if (choice == "del")
fs.deleteFile();
else if (choice == "read")
fs.read();
else if (choice == "dir")
fs.dir();
else if (choice == "write")
fs.write();
else if (choice == "format")
fs.format();
else if (choice == "clear")
{
system("CLS");
help();
}
else if (choice == "exit")
{
fs.save();
system("CLS");
cout << "系统正在注销...."<< endl;
Sleep(3);
return 0;
}
else if (choice == "help")
{
help();
}
else
{
cout << "命令错误,请重新输入" << endl;
}
}
}
}
void login(char name[30], char pass[30])
{
char pass2[SIZE];
while (true)
{
cout << "欢迎登录模拟文件系统" << endl;
cout << "账户:" << name << endl;
cout << "密码:";
cin >> pass2;
if (strcmp(pass, pass2) == 0)
{
cout << "密码正确!" << endl;
cout << "正在登录..." << endl;
Sleep(1000);
break;
}
else
cout << "密码错误,请重试" << endl;
Sleep(1000);
system("cls");
}
}
void runFun() {
char name[30] = "chensl", pass[30] = "123456";
login(name, pass);
system("CLS");
Sleep(2);
func(name, pass);
}
main.cpp
#include "filesystem.h"
int main() {
runFun();
return 0;
}