当前位置: 首页 > article >正文

基于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

http://www.kler.cn/a/451628.html

相关文章:

  • JAVAweb学习日记(三)Ajax
  • 【MinIO系列】MinIO Client (mc) 完全指南
  • 教培行业数字化未来:一站​式开发在线教育系统源码与网校APP详解
  • asp.net core webapi项目中 在生产环境中 进不去swagger
  • Python选择题训练工具:高效学习、答题回顾与音频朗读一站式体验
  • 重温设计模式--2、设计模式七大原则
  • 基于STM32 USB接口的温度控制器设计
  • 基于SpringBoot在线音乐系统平台功能实现十二
  • 【华为OD-E卷-狼羊过河 100分(python、java、c++、js、c)】
  • 2002 - Can‘t connect to server on ‘192.168.1.XX‘ (36)
  • 母婴用品系统|Java|SSM|JSP|
  • Text2Reward学习笔记
  • 消息队列(二)消息队列的高可用原理
  • 面试场景题系列:设计一致性哈希系统
  • vue实现2048小游戏
  • DP83848以太网移植流程,可以TCP通信
  • element-puls封装表单验证
  • python中使用selenium执行组合快捷键ctrl+v不生效问题
  • C++ 的大括号的用法合集
  • Hive与HBase的区别有哪些
  • 商城小程序开发有哪些流程?传统商家如何抓住小程序的流量!
  • 【Python 图片下载器】一款专门为爬虫制作的图片下载器,多线程下载,速度快,支持续传/图片缩放/图片压缩/图片转换
  • 项目练习:element-ui的valid表单验证功能用法
  • 常见API
  • 【Rust自学】6.2. Option枚举
  • Log4j1.27配置日志输出级别不起效