基于C#实现的(WinForm)模拟操作系统文件管理系统

基于C# Framework实现的模拟操作系统文件管理系统(文件管理大作业)

1. 使用说明

1.1 项目简介

文件(File)是操作系统中的一个重要概念。在系统运行时,计算机以进程为基本单位进行资源的调度和分配;而在用户进行的输入、输出中,则以文件为基本单位。大多数应用程序的输入都是通过文件来实现的,其输出也都保存在文件中,以便信息的长期存及将来的访问。当用户将文件用于应用程序的输入、输出时,还希望可以访问文件、修改文件和保存文件等,实现对文件的维护管理,这就需要系统提供一个文件管理系统,操作系统中的文件系统(File System)就是用于实现用户的这些管理要求。

基于此,为加深对操作系统文件系统的理解,设计一个文件系统模拟程序。

1.2 项目目的

  • 理解文件存储空间的管理;
  • 掌握文件的物理结构、目录结构和文件操作;
  • 实现简单文件系统管理;
  • 加深文件系统实现过程的理解;

1.3 项目功能要求

1.3.1 基本要求

  • 在内存中开辟一个空间作为文件存储器,在其上实现一个简单的文件系统;
  • 退出这个文件系统时,需要该文件系统的内容保存到磁盘上,以便下次可以将其回复到内存中来。

1.3.2 具体要求

  • 文件存储空间管理可采取显式链接(如FAT)或者其他方法;
  • 空闲空间管理可采用位图或者其他方法;
  • 文件目录采用多级目录结构,目录项目中应包含:文件名、物理地址、长度等信息。

1.3.3 文件系统提供的操作

  • 格式化
  • 创建子目录
  • 删除子目录
  • 显示目录
  • 更改当前目录
  • 创建文件
  • 打开文件
  • 关闭文件
  • 写文件
  • 读文件
  • 删除文件

1.4 操作手册

1.4.1 窗口内容

1.4.2 新建文件/文件夹

以文件为例(文件夹操作相同):

菜单->文件->新建->文件(文件夹)或 右键菜单->新建->文件(文件夹)

输入文件名:

创建成功:

1.4.3 删除文件

选择文件->右键->删除

删除成功:

1.4.4 读写文件内容:

双击1.txt,打开文件,输入内容

点击关闭,提示保存

再次打开,文件读入:

1.4.5 重命名

选中文件/文件夹,右键,重命名

输入新名字

重命名成功:

1.4.6 详细信息

选中文件/文件夹,右键,详细信息

展示详细信息:

1.4.7 目录切换

双击文件夹,进入子目录

点击返回按钮,返回子目录

1.4.8 格式化

点击格式化按钮

格式化成功

2. 程序设计与实现

2.1 设计

2.1.1 整体设计

2.1.1.1 主要设置

**物理空间分配:**物理块大小:512 Bits,空间大小:1000000个物理块,总计约512 MB大小。

**文件存储物理结构:**链接(串联)结构

**位图管理:**1000000/8=125000个字节即可表示所有物理块

**目录结构:**多级目录结构------树形目录

2.1.1.2 单文件管理

采用File表示文件类,建立FCB表示文件属性,FCB中存储文件类型、文件名、大小、创建时间、修改时间、文件路径、文件指针等信息。

2.1.1.3 文件目录管理

建立Catalog表示文件目录,建立Node类表示目录中的一个项,Node有两种类型:folder与file,其中folder不属于File类型而属于catalog类型,整体结构为多级Catalog的嵌套。

2.1.1.4 文件存储管理

采用链接(串联)结构作为物理结构,利用位图管理空闲空间,存储单位为大小为512 Bits的物理块。

2.1.1.5 将文件保存到磁盘

在系统关闭时,会将所需存储的变量进行二进制序列化操作,生成两个.dat 文件,保存到磁盘上,达到存储到磁盘上的目的。

在系统打开时,会在初始化函数里读取两个文件进行去序列化操作,并将其赋予相应的变量,达到读取磁盘上内容的目的。

2.1.2 数据结构设计

采用一个长为512字节的字符串来表示一个物理块

采用List结构存储一个文件的物理块链表

采用一个长为125000的bool数组作为位图

采用List来存储文件目录

2.2 主要类结构设计及实现

2.2.1 Block类

复制代码
public class Block
{
    private const int BLOCKSIZE = 512;  // 数据块大小为512Bytes
    private char[] data;  // 一个数据块可以存储512个Unicode字符
    private int length;   // 块所用长度
    //public int blockNumber = 0; //块号

    public Block()
    {
        data = new char[BLOCKSIZE];
    }

    public void setData(String new_data)
    {
        length = (new_data.Length > 512) ? 512 : new_data.Length;
        for (int i = 0; i < length; i++)
        {
            data[i] = new_data[i];
        }
    }

    public String getData()
    {
        String temp = new String(data);
        return temp;
    }
}

2.2.2 BitMap类

复制代码
public class BitMap
{
    private const int BYTESIZE = 8;    //字长,模拟一字节8位
    private const int CAPCITY = 100 * 100 * 100;    //内存空间最大块数(容量),521B*1000,000约512MB
    private const int BYTENUMBER = 100 * 100 * 100 / 8; //125000个字节即可表示所有块数
    public Block[] blocks = new Block[CAPCITY];    //所有块
    private bool[] bitMap = new bool[CAPCITY];     //位图

    //构造函数
    public BitMap()
    {
        for (int i = 0; i < CAPCITY; i++)
        {
            //blocks[i].blockNumber = i;
            bitMap[i] = true;
        }
    }

    //寻找一个空块
    public int findFreeBlock()
    {
        int bytePointer = 0;    //字号
        int bitPointer = 0;     //位号
        while (bytePointer < BYTENUMBER)    //字号在限制范围内
        {
            if (bitMap[bytePointer * BYTESIZE + bitPointer])//寻找到空块
            {
                return (bytePointer * BYTESIZE + bitPointer);
            }
            else
            {
                bitPointer += 1;
                if (bitPointer == BYTESIZE)//位号超出限制
                {
                    bitPointer = bitPointer % BYTESIZE;
                    bytePointer += 1;
                }
            }
        }
        return -1;
    }

    //置某一结点为空闲
    public void setFree(int i)
    {
        bitMap[i] = true;
    }

    //置某一结点为占用
    public void setOccupy(int i)
    {
        bitMap[i] = false;
    }
}private const int BYTESIZE = 8;    //字长,模拟一字节8位
private const int CAPCITY = 100 * 100 * 100;    //内存空间最大块数(容量),521B*1000,000约512MB
private const int BYTENUMBER = 100 * 100 * 100 / 8; //125000个字节即可表示所有块数
public Block[] blocks = new Block[CAPCITY];    //所有块
private bool[] bitMap = new bool[CAPCITY];     //位图

2.2.3 FCB类

复制代码
public class FCB
{
    public enum FileType { txt };  // 文件类型枚举
    public FileType fileType;   //文件类型
    public int fileSize;  // 文件大小
    public String fileName;  // 文件名
    public DateTime createdTime;  // 创建时间
    public DateTime updatedTime;  // 修改时间
    public List<Block> blocklist;      // 文件指针
    public String path;
}

2.2.4 File类

复制代码
public class File
{
    public FCB fcb = new FCB();                // FCB

    //构造函数
    public File(String name, String type, String fatherPath)
    {
        fcb.fileType = FCB.FileType.txt;
        fcb.fileName = name;
        fcb.createdTime = DateTime.Now;
        fcb.updatedTime = DateTime.Now;
        fcb.fileSize = 0;
        fcb.blocklist = new List<Block>();
        fcb.path = fatherPath + "\\" + name;
    }

    //清空文件块
    public void setEmpty(ref BitMap bitmap)
    {
        for(int i=0; i < fcb.blocklist.Count(); i+=1)
        {
            bitmap.setFree(bitmap.findFreeBlock()); //置该块为空闲
        }
        fcb.blocklist.Clear();                      //清空块链表
        fcb.fileSize = 0;                           //文件大小置为0
    }

    //写文件
    public void write(String data, ref BitMap bitmap)
    {
        setEmpty(ref bitmap);
        while (data.Count() > 512)
        {
            bitmap.blocks[bitmap.findFreeBlock()] = new Block();
            bitmap.blocks[bitmap.findFreeBlock()].setData(data.Substring(0, 512));   //每次截取512个字符加入寻找到的块中
            fcb.blocklist.Add(bitmap.blocks[bitmap.findFreeBlock()]);                //将块加入块链表
            bitmap.setOccupy(bitmap.findFreeBlock());                                //置此块为占用状态
            fcb.fileSize += 512;
            data = data.Remove(0,512);
        }
        bitmap.blocks[bitmap.findFreeBlock()] = new Block();
        bitmap.blocks[bitmap.findFreeBlock()].setData(data);
        fcb.blocklist.Add(bitmap.blocks[bitmap.findFreeBlock()]);                //将块加入块链表
        bitmap.setOccupy(bitmap.findFreeBlock());
        fcb.fileSize += data.Length;
        fcb.updatedTime = DateTime.Now;
    }

    //读文件
    //获取文件内容
    public String getData()
    {
        string content = "";
        for (int i = 0; i < fcb.blocklist.Count(); i += 1)
        {
            content += fcb.blocklist[i].getData();
        }
        return content;
    }
    //获取文件名称
    public String getName()
    {
        return fcb.fileName;
    }
    //获取文件大小,单位为Byte
    public int getfileSize()
    {
        return fcb.fileSize;
    }
    //获取文件创建时间
    public DateTime getcreatedTime()
    {
        return fcb.createdTime;
    }
    //获取文件修改时间
    public DateTime getupdatedTime()
    {
        return fcb.updatedTime;
    }
}

2.2.5 Node类

复制代码
public class Node
{
    public enum NodeType { folder, file };  // 结点类型
    public NodeType nodeType;   //结点类型
    public File file;           //节点内容
    public Catalog folder;      //节点内容
    public String path;  // 路径
    public String name;  // 名字

    public Node(String namedata, String fatherPath)   //文件夹结点
    {
        nodeType = NodeType.folder;
        path = fatherPath + "\\" + namedata;
        name = namedata;
        folder = new Catalog(namedata, fatherPath);
    }

    public Node(String namedata, String fileType, String fatherPath)    //文件结点
    {
        nodeType = NodeType.file;
        path = fatherPath + '\\' + namedata;
        name = namedata;
        file = new File(name, fileType, fatherPath);
    }

    public void changeName(String changed_name)
    {
        name = changed_name;
        switch (nodeType)
        {
            case Node.NodeType.folder:
                folder.path = folder.path.Remove(folder.path.Length-folder.name.Length-1,folder.name.Length+1);
                folder.name = changed_name;
                folder.path = folder.path + "\\" + folder.name;
                break;
            case Node.NodeType.file:
                file.fcb.path = file.fcb.path.Remove(file.fcb.path.Length - file.fcb.fileName.Length - 1, file.fcb.fileName.Length + 1);
                file.fcb.fileName = changed_name;
                file.fcb.path = file.fcb.path + "\\" + file.fcb.fileName;
                break;
            default:
                break;
        }
    }
}

2.2.6 Catalog类

复制代码
public class Catalog
{
    public List<Node> nodelist; //目录中只含结点
    public int childrenNum;  // 子结点的数量
    public String name;  // 名字
    public String path;  //路径
    public int fileSize;  // 文件大小
    public DateTime createdTime;  // 创建时间
    public DateTime updatedTime;  // 修改时间
    public Catalog parent_catalog = null; //父母节点

    //其他目录
    public Catalog(String namedata, String fatherPath)
    {
        nodelist = new List<Node>();
        name = namedata;
        path = fatherPath + '\\' + namedata;
        createdTime = DateTime.Now;
        updatedTime = DateTime.Now;
        fileSize = 0;
        childrenNum = 0;
    }

    //根目录
    public Catalog(String namedata)
    {
        nodelist = new List<Node>();
        name = namedata;
        path = namedata + ":\\";
        createdTime = DateTime.Now;
        updatedTime = DateTime.Now;
        fileSize = 0;
        childrenNum = 0;
    }

    //添加文件夹结点
    public void addNode(Catalog par_catalog, String namedata, String fatherPath)
    {
        Node node = new Node(namedata, fatherPath);
        node.folder.parent_catalog = par_catalog;
        nodelist.Add(node);
        childrenNum += 1;
        updatedTime = DateTime.Now;
    }

    //添加文件结点
    public void addNode(String namedata, String fileType, String fatherPath)
    {
        Node node = new Node(namedata, fileType, fatherPath);
        nodelist.Add(node);
        childrenNum += 1;
        updatedTime = DateTime.Now;
    }
}

3. 边界测试

3.1 已返回到根目录再返回

**测试用例:**在下图情况下进行测试,点击返回按钮

**测试结果:**系统给出提示,已是根目录。

3.2 空间为空时进行格式化

**测试用例:**在下图情况下进行测试,点击格式化

**测试结果:**无变化,系统正常运行

3.3 新建文件重名

**测试用例:**在下图情况下进行测试,创建一个名字为1的文件

**测试结果:**首先检测当前目录下内容,自动更改默认名字为New File(1),输入1后,新建文件名如下:

附录

6.1 文件说明

executablefile文件夹:可执行文件

FileManagement文件夹:由Visual Studio生成的项目文件,包括.sln文件以及项目代码

readme文件夹:项目文档

6.2 开发环境

  • 操作系统:windows10 1803 64bit
  • 语言:C#(FrameWork)
  • 开发环境:Visual Studio Community 2017 15.9.10
相关推荐
glumes1 小时前
音视频教程-第二节
ffmpeg
HalvmånEver2 小时前
7.高并发内存池大页内存申请释放以及使用定长内存池脱离new
java·spring boot·spring
凤山老林2 小时前
SpringBoot 使用 H2 文本数据库构建轻量级应用
java·数据库·spring boot·后端
摇滚侠2 小时前
git 把已经推送到远程仓库的文件取消被 git 管理
git
赶路人儿2 小时前
UTC时间和时间戳介绍
java·开发语言
dreamread2 小时前
【SpringBoot整合系列】SpringBoot3.x整合Swagger
java·spring boot·后端
6+h2 小时前
【java】基本数据类型与包装类:拆箱装箱机制
java·开发语言·python
007张三丰3 小时前
掌握核心!Git最常用的15个命令行:从入门到实战详解
git·gitlab·github·git命令行·常用命令行
一直都在5723 小时前
Spring面经
java·后端·spring
xiaoye37083 小时前
如何在Spring中使用注解配置Bean的生命周期回调方法?
java·spring