【从零实现一个简易文件系统:C++ 模拟 FAT 表与目录管理】

从零实现一个简易文件系统:C++ 模拟 FAT 表与目录管理

前言:为什么需要理解文件系统?

在计算机科学的学习中,文件系统是一个核心但抽象的概念。虽然我们每天都在使用 lscdmkdir 等命令,但很少有人真正理解这些命令背后是如何实现的。本文将通过一个完整的 C++ 模拟项目,带你深入理解文件系统的核心机制,包括:

  • FAT(文件分配表) 如何管理磁盘块
  • 目录结构 如何组织文件和子目录
  • FCB(文件控制块) 如何存储文件元数据
  • 打开文件表 如何管理文件访问

通过这个项目,你不仅能掌握文件系统的基本原理,还能获得一个可以运行、可以扩展的完整代码实现。

一、项目概述与核心设计

1.1 项目目标

  • 模拟一个支持基本文件操作(创建、删除、读写)和目录操作(创建、删除、切换)的简易文件系统
  • 实现 FAT 表管理、目录结构、文件控制块等核心数据结构
  • 提供交互式命令行界面,支持常见的文件系统命令

1.2 系统架构设计

  • 磁盘模拟层:使用内存模拟物理磁盘,划分固定大小的块
  • FAT 管理层:实现文件分配表的创建、查找和释放
  • 目录管理层:实现树形目录结构,支持路径解析
  • 文件操作层:实现文件的打开、关闭、读写操作
  • 用户接口层:提供交互式命令行界面

1.3 关键技术指标

  • 磁盘大小:128 个块 × 512 字节 = 64KB
  • 最大打开文件数:5 个
  • 文件名长度:最大 15 个字符
  • 支持文件类型:普通文件、目录文件

二、核心数据结构详解

2.1 文件控制块(FCB)

2.2 目录文件结构

2.3 磁盘结构

2.4 打开文件表

三、关键功能实现步骤

3.1 系统初始化与格式化

3.2 目录管理实现

  • mkdir:创建目录的完整流程
  • rmdir:删除目录的安全检查
  • cd:目录切换与路径管理
  • ls:目录内容显示

3.3 文件操作实现

  • create:创建空文件
  • destroy:删除文件
  • open/close:文件打开与关闭
  • write/read:文件读写操作

3.4 系统命令实现

  • format:磁盘格式化
  • clear:清屏命令(跨平台)
  • help:帮助信息显示
  • exit:系统安全退出

四、代码实现详解

4.1 主函数流程

4.2 命令解析与分发

4.3 内存与磁盘同步

五、运行与测试

5.1 编译与运行

5.2 基本功能测试

5.3 边界条件测试

六、扩展与优化建议

6.1 功能扩展

  • 支持多级子目录
  • 实现文件复制和移动
  • 添加文件权限控制
  • 支持软链接和硬链接

6.2 性能优化

  • 使用哈希表加速文件查找
  • 实现磁盘块缓存机制
  • 支持大文件(多块分配)
  • 添加日志恢复功能

6.3 代码优化

  • 使用面向对象重构
  • 添加异常处理机制
  • 实现配置文件读取
  • 增加单元测试

七、总结与收获

7.1 技术要点总结

  • 理解了 FAT 文件系统的基本原理
  • 掌握了目录树的数据结构设计
  • 学会了文件系统命令的实现方法
  • 实践了磁盘模拟和持久化存储

7.2 学习价值

  • 理论联系实际:将抽象的文件系统概念转化为具体代码
  • 系统编程能力:深入理解操作系统底层机制
  • 调试与测试:学习复杂系统的调试方法
  • 项目架构:掌握中型项目的模块化设计

7.3 后续学习方向

  • 研究 Linux ext 文件系统
  • 学习分布式文件系统(如 HDFS)
  • 探索现代文件系统(如 ZFS、Btrfs)
  • 了解文件系统与数据库的融合趋势

八、参考资料

8.1 推荐书籍

  • 《操作系统概念》(Abraham Silberschatz)
  • 《现代操作系统》(Andrew S. Tanenbaum)
  • 《深入理解计算机系统》(Randal E. Bryant)

8.2 在线资源

8.3 相关项目

  • FUSE(用户空间文件系统)
  • Minix 文件系统
  • FAT32 开源实现
  • 教学用文件系统(xv6、OS161)

项目源码:本文提供的完整 C++ 代码可以直接编译运行,建议读者在理解的基础上进行修改和扩展,加深对文件系统原理的理解。

cpp 复制代码
#include <stdio.h>
#include <memory.h>
#include <string.h>
#include <iostream>
#include <time.h>
#include <stdlib.h>
#include <string>
#include <algorithm>
using namespace std;

#define GENERAL 1    // 普通文件
#define DIRECTORY 2  // 目录文件
#define Zero 0       // 空文件/未使用

//FCB存储结构
struct FCB
{
    char fname[16];      // 文件名
    char type;           // 0:空文件  1:普通文件 2:目录文件
    int size;            // 文件大小
    int fatherBlockNum;  // 当前父目录块号
    int currentBlockNum; // 当前块号
    char Dir_Time[25];   // 目录创建时间
    char File_Time[25];  // 文件修改时间

    // 初始化函数
    void initialize()
    {
        memset(fname, 0, sizeof(fname));
        type = Zero;
        size = 0;
        fatherBlockNum = currentBlockNum = 0;
        memset(Dir_Time, 0, sizeof(Dir_Time));
        memset(File_Time, 0, sizeof(File_Time));
    }
};

//文件系统初始化参数设置
const char* FilePath = "../filesystemlab/root/file"; // 初始文件目录,注意运行前需要rm -rf file删除旧的文件系统数据文件 file
const int BlockSize = 512;                           // 块大小
const int OPEN_MAX = 5;                              // 最多打开文件数
const int BlockCount = 128;                          // 块数量
const int DiskSize = BlockSize * BlockCount;         // 磁盘大小
const int BlockFcbCount = BlockSize/sizeof(FCB);     // 目录文件可存储FCB数
int OpenFileCount = 0;                               // 统计当前打开文件数目

//用户文件打开表
struct OPENLIST
{
    int files;                  // 当前打开文件数
    FCB f[OPEN_MAX];            // f[OPEN_MAX]:数组存储每个打开文件的 FCB,初始化时将fatherBlockNum设为 - 1(标记未使用),type默认设为普通文件。
    OPENLIST()
    {
        files = 0;  //当前打开文件数,与全局OpenFileCount同步
        for(int i = 0; i < OPEN_MAX; i++){
            f[i].fatherBlockNum = -1;  //-1标记未使用
            f[i].type = GENERAL;  //默认设为普通文件
        }
    }
};
//目录文件结构
struct dirFile
{
    struct FCB fcb[BlockFcbCount];  //目录下的所有FCB(目录项)

    // 初始化目录:父块号, 当前块号, 目录名
    void init(int _FatherBlockNum, int _CurrentBlockNum, char *name)
    {
        // 设置当前目录FCB
        strncpy(fcb[0].fname, name, sizeof(fcb[0].fname)-1);
        fcb[0].fatherBlockNum = _FatherBlockNum;
        fcb[0].currentBlockNum = _CurrentBlockNum;
        fcb[0].type = DIRECTORY;

        // 设置创建时间
        time_t now = time(NULL);
        strncpy(fcb[0].Dir_Time, ctime(&now), sizeof(fcb[0].Dir_Time)-1);
        fcb[0].Dir_Time[24] = '\0';

        // 初始化剩余FCB为"空",父块号指向当前目录块
        for(int i = 1; i < BlockFcbCount; i++){
            fcb[i].initialize();
            fcb[i].fatherBlockNum = _CurrentBlockNum;
        }
    }
};
//磁盘结构及格式化
struct DISK
{
    int FAT1[BlockCount];     // FAT1表(文件分配表,主表)
    int FAT2[BlockCount];     // FAT2表(文件分配表,备份)
    struct dirFile root;      // root为根目录块(固定占用第2块)
    char data[BlockCount-3][BlockSize];  // 数据区(从第3块开始)

    void format(){
        // 初始化FAT表
        memset(FAT1, 0, sizeof(FAT1));
        memset(FAT2, 0, sizeof(FAT2));

        // 0,1,2块分别用于FAT1,FAT2,根目录,标记为-2(系统块,不可用)
        FAT1[0] = FAT1[1] = FAT1[2] = -2;
        FAT2[0] = FAT2[1] = FAT2[2] = -2;

        // 初始化根目录(父块号=2,当前块号=2,目录名指定路径)
        root.init(2, 2, (char *)"../filesystemlab/root/");

        // 初始化数据区为0
        memset(data, 0, sizeof(data));
    }
};

// 全局变量定义
FILE *fp;                      // 磁盘文件指针
char * BaseAddr;               // 磁盘空间基地址
string currentPath = "../filesystemlab/root/file/";  // 当前工作目录路径
int current = 2;               // 当前目录块号(初始为根目录块2)
string cmd;                    // 存储用户输入的命令
struct DISK *osPoint;          // 指向模拟磁盘的指针(BaseAddr强转而来)
char command[16];              // 存储命令参数(如mkdir后的目录名)
struct OPENLIST* openlist;     // 打开文件列表指针

//命令集声明
int format();  //磁盘操作:format(格式化)
int mkdir(char *sonfname);  //目录管理:mkdir(创建目录)
int rmdir(char *sonfname);  //目录管理:rmdir(删除目录)
int create(char *name);  //文件管理:create(创建文件)
int listshow();  //目录管理:listshow(ls,列出目录内容)
int destroy(char *name);  //文件管理:destroy(rm,删除文件)
int changePath(char *sonfname);  //目录管理:changePath(cd,切换目录)
int write(char *name);  //文件操作:write(写文件)
int exit_sys();  //文件操作:read(读文件)
int open(char *file);  //文件操作:open(打开文件)
int close(char *file);  //文件操作:close(关闭文件)
int read(char *file);  //文件操作:read(读文件)
void setCurrentTime(char *timeStr);

//设置当前时间戳
void setCurrentTime(char *timeStr)
{
    time_t now = time(NULL);
    strncpy(timeStr, ctime(&now), 24);
    timeStr[24] = '\0';
}

/************************************************************************/
/* 文件系统初始化/格式化实现                                           */
/************************************************************************/
int format()
{
    osPoint->format();
    current = 2;  // 回到根目录
    currentPath = "../filesystemlab/root/file/";
    printf("磁盘已成功格式化文件系统!\n");
    return 1;
}

/************************************************************************/
/* 创建目录实现                                                        */
/************************************************************************/
int mkdir(char *sonfname)
{
    // 检查目录名长度
    if(strlen(sonfname) >= 16){
        printf("目录名过长(最大15字符)!\n");
        return -1;
    }

    dirFile &currentDir = *(dirFile *)&osPoint->data[current - 3];

    // 检查目录是否已存在
    for (int i = 0; i < BlockFcbCount; ++i)
    {
        if (currentDir.fcb[i].type != Zero && strcmp(currentDir.fcb[i].fname, sonfname) == 0)
        {
            printf("目录已存在!\n");
            return -1;
        }
    }

    // 寻找空FCB位置
    int emptyFcbIdx = -1;
    for (int i = 0; i < BlockFcbCount; ++i)
    {
        if (currentDir.fcb[i].type == Zero)
        {
            emptyFcbIdx = i;
            break;
        }
    }

    if (emptyFcbIdx == -1)
    {
        printf("当前目录已满,无法创建新目录!\n");
        return -1;
    }

    // 寻找空闲块
    int newBlock = -1;
    for (int j = 3; j < BlockCount; ++j)
    {
        if (osPoint->FAT1[j] == 0)
        {
            newBlock = j;
            break;
        }
    }

    if (newBlock == -1)
    {
        printf("磁盘空间不足!\n");
        return -1;
    }

    // 标记FAT表
    osPoint->FAT1[newBlock] = -1;
    osPoint->FAT2[newBlock] = -1;

    // 初始化新目录FCB
    currentDir.fcb[emptyFcbIdx].type = DIRECTORY;
    strcpy(currentDir.fcb[emptyFcbIdx].fname, sonfname);
    currentDir.fcb[emptyFcbIdx].fatherBlockNum = current;
    currentDir.fcb[emptyFcbIdx].currentBlockNum = newBlock;
    setCurrentTime(currentDir.fcb[emptyFcbIdx].Dir_Time);

    // 初始化新目录
    dirFile &newDir = *(dirFile *)&osPoint->data[newBlock - 3];
    newDir.init(current, newBlock, sonfname);

    printf("目录创建成功!\n");
    return 1;
}

/************************************************************************/
/* 删除目录实现                                                        */
/************************************************************************/
int rmdir(char *sonfname)
{
    dirFile &currentDir = *(dirFile *)&osPoint->data[current - 3];

    // 查找要删除的目录
    for (int i = 0; i < BlockFcbCount; ++i)
    {
        if (currentDir.fcb[i].type == DIRECTORY && strcmp(currentDir.fcb[i].fname, sonfname) == 0)
        {
            int blockNum = currentDir.fcb[i].currentBlockNum;
            dirFile &subDir = *(dirFile *)&osPoint->data[blockNum - 3];

            // 检查目录是否为空
            bool isEmpty = true;
            for (int j = 1; j < BlockFcbCount; ++j)
            {
                if (subDir.fcb[j].type != Zero)
                {
                    isEmpty = false;
                    break;
                }
            }

            if (!isEmpty)
            {
                printf("目录非空,无法删除!\n");
                return -1;
            }

            // 释放块
            osPoint->FAT1[blockNum] = 0;
            osPoint->FAT2[blockNum] = 0;

            // 清空FCB
            currentDir.fcb[i].initialize();

            printf("目录删除成功!\n");
            return 1;
        }
    }

    printf("目录不存在!\n");
    return -1;
}

/************************************************************************/
/* 创建文件实现                                                        */
/************************************************************************/
int create(char *name)
{
    // 检查文件名长度
    if(strlen(name) >= 16){
        printf("文件名过长(最大15字符)!\n");
        return -1;
    }

    dirFile &currentDir = *(dirFile *)&osPoint->data[current - 3];

    // 检查文件是否已存在
    for (int i = 0; i < BlockFcbCount; ++i)
    {
        if (currentDir.fcb[i].type != Zero && strcmp(currentDir.fcb[i].fname, name) == 0)
        {
            printf("文件已存在!\n");
            return -1;
        }
    }

    // 寻找空FCB位置
    int emptyFcbIdx = -1;
    for (int i = 0; i < BlockFcbCount; ++i)
    {
        if (currentDir.fcb[i].type == Zero)
        {
            emptyFcbIdx = i;
            break;
        }
    }

    if (emptyFcbIdx == -1)
    {
        printf("当前目录已满,无法创建新文件!\n");
        return -1;
    }

    // 寻找空闲块
    int newBlock = -1;
    for (int j = 3; j < BlockCount; ++j)
    {
        if (osPoint->FAT1[j] == 0)
        {
            newBlock = j;
            break;
        }
    }

    if (newBlock == -1)
    {
        printf("磁盘空间不足!\n");
        return -1;
    }

    // 标记FAT表
    osPoint->FAT1[newBlock] = -1;
    osPoint->FAT2[newBlock] = -1;

    // 初始化文件FCB
    currentDir.fcb[emptyFcbIdx].type = GENERAL;
    strcpy(currentDir.fcb[emptyFcbIdx].fname, name);
    currentDir.fcb[emptyFcbIdx].fatherBlockNum = current;
    currentDir.fcb[emptyFcbIdx].currentBlockNum = newBlock;
    currentDir.fcb[emptyFcbIdx].size = 0;
    setCurrentTime(currentDir.fcb[emptyFcbIdx].File_Time);

    printf("文件创建成功!\n");
    return 1;
}

/************************************************************************/
/* 列出文件/目录实现                                                   */
/************************************************************************/
int listshow()
{
    dirFile &currentDir = *(dirFile *)&osPoint->data[current - 3];
    printf("当前目录内容:\n");
    printf("名称\t\t类型\t大小\t最后修改时间\n");
    printf("--------------------------------------------\n");

    for (int i = 0; i < BlockFcbCount; ++i)
    {
        if (currentDir.fcb[i].type != Zero)
        {
            printf("%-16s\t", currentDir.fcb[i].fname);
            printf("%s\t", currentDir.fcb[i].type == DIRECTORY ? "目录" : "文件");
            printf("%d\t", currentDir.fcb[i].size);

            if(currentDir.fcb[i].type == DIRECTORY){
                printf("%s\n", currentDir.fcb[i].Dir_Time);
            }else{
                printf("%s\n", currentDir.fcb[i].File_Time);
            }
        }
    }
    return 1;
}

/************************************************************************/
/* 删除文件实现                                                        */
/************************************************************************/
int destroy(char *name)
{
    dirFile &currentDir = *(dirFile *)&osPoint->data[current - 3];

    // 先检查文件是否打开
    for(int i = 0; i < OpenFileCount; i++){
        if(strcmp(openlist->f[i].fname, name) == 0){
            printf("文件正在打开中,无法删除!\n");
            return -1;
        }
    }

    // 查找并删除文件
    for (int i = 0; i < BlockFcbCount; ++i)
    {
        if (currentDir.fcb[i].type == GENERAL && strcmp(currentDir.fcb[i].fname, name) == 0)
        {
            int blockNum = currentDir.fcb[i].currentBlockNum;

            // 释放块
            osPoint->FAT1[blockNum] = 0;
            osPoint->FAT2[blockNum] = 0;

            // 清空FCB
            currentDir.fcb[i].initialize();

            printf("文件删除成功!\n");
            return 1;
        }
    }

    printf("文件不存在!\n");
    return -1;
}

/************************************************************************/
/* 切换目录实现                                                        */
/************************************************************************/
int changePath(char *sonfname)
{
    dirFile &currentDir = *(dirFile *)&osPoint->data[current - 3];

    // 返回上一级目录
    if (strcmp(sonfname, "..") == 0)
    {
        if (current == 2)
        {
            printf("已经是根目录!\n");
            return -1;
        }

        // 获取父目录块号
        current = currentDir.fcb[0].fatherBlockNum;

        // 更新路径
        size_t lastSlash = currentPath.find_last_of('/', currentPath.length() - 2);
        if(lastSlash != string::npos){
            currentPath = currentPath.substr(0, lastSlash + 1);
        }

        return 1;
    }

    // 进入子目录
    for (int i = 0; i < BlockFcbCount; ++i)
    {
        if (currentDir.fcb[i].type == DIRECTORY && strcmp(currentDir.fcb[i].fname, sonfname) == 0)
        {
            current = currentDir.fcb[i].currentBlockNum;
            currentPath += sonfname;
            currentPath += "/";
            return 1;
        }
    }

    printf("目录不存在!\n");
    return -1;
}

/************************************************************************/
/* 系统退出实现                                                        */
/************************************************************************/
int exit_sys()
{
    // 保存磁盘数据
    if ((fp = fopen(FilePath, "wb")) != NULL)
    {
        fwrite(BaseAddr, sizeof(char), DiskSize, fp);
        fclose(fp);
        printf("磁盘已保存!\n");
    }
    else
    {
        printf("磁盘保存失败!\n");
        return -1;
    }

    // 释放内存
    free(BaseAddr);
    delete openlist;

    return 1;
}

/************************************************************************/
/* 写文件                                                               */
/************************************************************************/
int write(char *name)
{
    dirFile &currentDir = *(dirFile *)&osPoint->data[current - 3];

    // 查找文件
    for (int i = 0; i < BlockFcbCount; ++i)
    {
        if (currentDir.fcb[i].type == GENERAL && strcmp(currentDir.fcb[i].fname, name) == 0)
        {
            int blockNum = currentDir.fcb[i].currentBlockNum;

            // 检查块号有效性
            if (blockNum < 3 || blockNum >= BlockCount)
            {
                printf("文件块号无效!\n");
                return -1;
            }

            // 读取输入数据
            printf("请输入要写入的数据(输入'EOF'结束):\n");
            string input, data;

            // 清空输入缓冲区
            cin.ignore();

            while (getline(cin, input) && input != "EOF")
            {
                data += input + "\n";
            }

            // 检查数据大小
            if (data.size() > BlockSize)
            {
                printf("数据过大(最大%d字节),无法写入!\n", BlockSize);
                return -1;
            }

            // 写入数据
            memset(osPoint->data[blockNum - 3], 0, BlockSize);
            memcpy(osPoint->data[blockNum - 3], data.c_str(), data.size());

            // 更新文件信息
            currentDir.fcb[i].size = data.size();
            setCurrentTime(currentDir.fcb[i].File_Time);

            printf("写入成功!共写入%d字节\n", data.size());
            return 1;
        }
    }

    printf("文件不存在!\n");
    return -1;
}

/************************************************************************/
/* 读取文件                                                             */
/************************************************************************/
int read(char *file)
{
    dirFile &currentDir = *(dirFile *)&osPoint->data[current - 3];

    // 查找文件
    for (int i = 0; i < BlockFcbCount; ++i)
    {
        if (currentDir.fcb[i].type == GENERAL && strcmp(currentDir.fcb[i].fname, file) == 0)
        {
            int blockNum = currentDir.fcb[i].currentBlockNum;

            // 检查块号有效性
            if (blockNum < 3 || blockNum >= BlockCount)
            {
                printf("文件块号无效!\n");
                return -1;
            }

            // 读取文件内容
            char buffer[BlockSize + 1] = {0};
            memcpy(buffer, osPoint->data[blockNum - 3], currentDir.fcb[i].size);

            // 显示文件信息和内容
            printf("文件名称:%s\n", currentDir.fcb[i].fname);
            printf("文件大小:%d字节\n", currentDir.fcb[i].size);
            printf("最后修改:%s\n", currentDir.fcb[i].File_Time);
            printf("文件内容:\n");
            printf("------------------------\n");
            printf("%s\n", buffer);
            printf("------------------------\n");

            return 1;
        }
    }

    printf("文件不存在!\n");
    return -1;
}

/************************************************************************/
/* 打开文件                                                             */
/************************************************************************/
int open(char *file)
{
    dirFile &currentDir = *(dirFile *)&osPoint->data[current - 3];

    // 检查是否已打开
    for(int i = 0; i < OpenFileCount; i++){
        if(strcmp(openlist->f[i].fname, file) == 0){
            printf("文件已打开!\n");
            return -1;
        }
    }

    // 查找文件
    for (int i = 0; i < BlockFcbCount; ++i)
    {
        if (currentDir.fcb[i].type == GENERAL && strcmp(currentDir.fcb[i].fname, file) == 0)
        {
            // 检查打开文件数限制
            if (OpenFileCount >= OPEN_MAX)
            {
                printf("打开文件数已达上限!\n");
                return -1;
            }

            // 添加到打开文件表
            openlist->f[OpenFileCount] = currentDir.fcb[i];
            OpenFileCount++;
            openlist->files = OpenFileCount;

            printf("文件打开成功!\n");
            return 1;
        }
    }

    printf("文件不存在!\n");
    return -1;
}

/************************************************************************/
/* 关闭文件                                                             */
/************************************************************************/
int close(char *file)
{
    // 查找打开的文件
    for (int i = 0; i < OpenFileCount; ++i)
    {
        if (strcmp(openlist->f[i].fname, file) == 0)
        {
            // 移动最后一个文件到当前位置
            openlist->f[i] = openlist->f[OpenFileCount - 1];

            // 清空最后一个位置
            openlist->f[OpenFileCount - 1].initialize();

            // 更新计数
            OpenFileCount--;
            openlist->files = OpenFileCount;

            printf("文件关闭成功!\n");
            return 1;
        }
    }

    printf("文件未打开!\n");
    return -1;
}

/************************************************************************/
/* 功能菜单显示                                                         */
/************************************************************************/
void MenuShow()
{
    printf(
        "************************************************************************\n"
        "*                            命令列表                                  *\n"
        "*         目录_创建:mkdir <dirname>                                  *\n"
        "*         目录_删除:rmdir <dirname>                                  *\n"
        "*         目录_显示:ls                                               *\n"
        "*         目录_切换:cd <dirname> (..返回上一级)                       *\n"
        "*         文件_创建:create <filename>                                *\n"
        "*         文件_写入:write <filename>                                 *\n"
        "*         文件_读取:read <filename>                                  *\n"
        "*         文件_打开:open <filename>                                  *\n"
        "*         文件_关闭:close <filename>                                 *\n"
        "*         文件_删除:rm <filename>                                    *\n"
        "*         系统_格式化:format                                         *\n"
        "*         系统_清屏:clear                                            *\n"
        "*         系统_退出:exit                                             *\n"
        "*         系统_帮助:help                                             *\n"
        "************************************************************************\n");
}

/************************************************************************/
/* 退出界面                                                             */
/************************************************************************/
void Menu_Exit()
{
    time_t now;
    now = time(NULL);
    char NOW[25];
    strncpy(NOW, ctime(&now), 24);
    NOW[24] = '\0';

    // 清屏(兼容Windows和Linux)
    #ifdef _WIN32
        system("cls");
    #else
        system("clear");
    #endif

    printf(
        "************************************************************************\n"
        "*                            文件系统                                  *\n"
        "************************************************************************\n"
        "***********************%s************************\n"
        "************************************************************************\n"
        "*                          感谢使用本系统                              *\n"
        "*                             下次再见                                 *\n"
        "************************************************************************\n", NOW);
}
//主函数
int main()
{
    // 显示帮助菜单
    MenuShow();

    // 初始化打开文件表
    openlist = new OPENLIST;

    // 分配磁盘空间
    BaseAddr = (char *)malloc(DiskSize);
    if(BaseAddr == NULL){
        printf("内存分配失败!\n");
        return -1;
    }

    // 初始化磁盘指针
    osPoint = (struct DISK *)(BaseAddr);

    // 加载或初始化磁盘
    if((fp = fopen(FilePath, "rb")) != NULL){
        // 读取已有磁盘数据
        fread(BaseAddr, sizeof(char), DiskSize, fp);
        fclose(fp);
        printf("\n磁盘已加载,路径:%s\n\n", FilePath);
    }
    else{
        // 初始化新磁盘
        printf("欢迎使用文件管理系统!\t正在初始化...\n");
        format();
        printf("初始化完成,可正常使用!祝您使用愉快!\n\n");
    }

    // 主命令循环
    while(1)
    {
        cout << currentPath << "> ";
        cin >> cmd;

        // 处理各种命令
        if(cmd == "format"){
            format();
        }
        else if(cmd == "mkdir"){
            cin >> command;
            mkdir(command);
        }
        else if(cmd == "rmdir"){
            cin >> command;
            rmdir(command);
        }
        else if(cmd == "ls"){
            listshow();
        }
        else if(cmd == "cd"){
            cin >> command;
            changePath(command);
        }
        else if(cmd == "create"){
            cin >> command;
            create(command);
        }
        else if(cmd == "write"){
            cin >> command;
            write(command);
        }
        else if(cmd == "read"){
            cin >> command;
            read(command);
        }
        else if(cmd == "rm"){
            cin >> command;
            destroy(command);
        }
        else if(cmd == "open"){
            cin >> command;
            open(command);
        }
        else if(cmd == "close"){
            cin >> command;
            close(command);
        }
        else if(cmd == "clear"){
            #ifdef _WIN32
                system("cls");
            #else
                system("clear");
            #endif
        }
        else if(cmd == "help"){
            MenuShow();
        }
        else if(cmd == "exit"){
            if(exit_sys() == 1) break;
        }
        else{
            cout << "命令无效,请重新输入!输入help查看帮助。" << endl;
        }
    }

    // 显示退出界面
    Menu_Exit();

    return 0;
}