实验:文件管理系统

一.实验目的:

通过编写一个简单的文件管理程序,实现主要的文件操作命令,加深操作系统对于文件目录管理方式的理解。应用文件管理的相关命令完成下列操作:建立文件、建立文件夹、复制文件及文件夹、移动文件及文件夹、删除文件及文件夹、显示文件夹中的内容、查看文件内容、修改文件权限、搜索文件等。

采用二级目录实现文件管理

.实验环境

硬件环境:计算机一台,局域网环境;

软件环境:Windows XP及以上版本 Professional操作系统平台,Visual C++ 6.0专业版或企业版。

三.实验提示

为简单起见,可假设假设文件物理结构为连续结构,编程模拟一个简单的文件系统,实现对文件的各种管理和控制功能。

1.文件目录采用二级目录结构,第一级为文件目录MFD,如图1所示;第二级为用户文件目录UFD,如图2所示。

用户名

用户文件目录地址

图1 MFD结构

文件名

文件保护方式

文件当前长度

文件最大长度

文件所在地址

图2 UFD结构

在UFD中,文件保护方式,用0表示文件可读;用1表示文件可读可写,执行,用2表示文件可写。

2.为加速文件存取,为每个用户建立一张用户打开文件表UOF,用以记录该用户当前正在使用的文件。假定最多允许打开4个文件,该表设置问4项,当打开文件个数超过4时,应给出出错信息。为此应该设置一个用户打开文件计数器,以控制文件打开个数,计数器初始化为0.UOF结构图如图3所示。

文件名

文件操作方式

读指针

写指针

文件当前长度

文件所在地址

状态

图3 UOF结构

在图3中,“文件操作方式”时指文件打开后要执行的操作,“状态”是指用户打开文件表的各个表象为空表目或被占用。读写指针用来指出文件的存取位置。出事状态下,读指针=1,写指针=文件长度,文件长度=0。

用户建立或打开一个文件时,将制定文件的说明信息登记在用户打开文件表中,其中为了给创建的文件分配磁盘空间,可引入一个计数器,用它来模拟磁盘使用情况,初始化为10。假定一个磁盘块大小为64个字节。

3.为该文件系统提供6条操作命令:创建、打开、读、写、关闭、删除、复制、粘贴等。要创建文件并向文件中保存信息时,用户程序应用create、write、close等3条命令来实现;当要读文件时,用户文件应使用open、read、close等3条命令来实现。

4.在该模拟系统中,应先建立主文件目录、用户文件目录和用户打开文件表,然后接受合法用户,给出一个菜单,按用户选择执行相应操作。

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
using namespace std;

//目录项结构:
struct dirUnit {
    char fileName[59];  //文件名
    char type;  //文件类型,0目录, 1文件
    int startBlock; //FCB起始盘块
};
//一个目录项包含了文件名和文件类型,当文件为目录时,起始盘块指示了目录表所在的盘块号,当文件为文件时,起始盘块指示了FCB所在的盘块号。
#define dirTable_max_size 15    //目录表项最大值

//目录表结构:
struct dirTable {
    int dirUnitAmount;//目录项数目
    dirUnit dirs[dirTable_max_size];//目录项列表
};

//FCB结构:
struct FCB {
    int blockNum;   //文件数据起始盘块号
    int fileSize;   //文件大小,盘块为单位
    int dataSize;   //已写入的内容大小,字节为单位
    int readptr;    //读指针,字节为单位
    int link;   //文件链接数
};

char* systemStartAddr;  //系统起始地址
#define block_count 100
#define system_size 100
#define block_szie 100

//初始化系统
void initSystem()
{
    //创建空间
    systemStartAddr = (char*)malloc(system_size * sizeof(char));
    //初始化盘块的位示图
    for (int i = 0; i < block_count; i++)
        systemStartAddr[i] = '0';
    //用于存放位示图的空间已被占用
    int bitMapSize = block_count * sizeof(char) / block_szie;//位示图占用盘块数:100
    for (int i = 0; i < bitMapSize; i++)//从零开始分配
        systemStartAddr[i] = '1';   //盘块已被使用
}
//退出系统
void exitSystem()
{
    free(systemStartAddr);
}
//磁盘分配
int getBlock(int blockSize)
{
    int startBlock = 0;
    int sum = 0;
    for (int i = 0; i < block_count; i++)
    {
        if (systemStartAddr[i] == '0')//可用盘块
        {
            if (sum == 0)//刚开始,设置开始盘块号
                startBlock = i;
            sum++;
            if (sum == blockSize)//连续盘块是否满足需求
            {
                //满足分配,置1
                for (int j = startBlock; j < startBlock + blockSize; j++)
                    systemStartAddr[j] = '1';
                return startBlock;
            }

        }
        else//已被使用,连续已经被打断
            sum = 0;
    }
    printf("not found such series memory Or memory is full\n");
    return -1;

}
//获得盘块的物理地址
char* getBlockAddr(int blockNum)
{
    return systemStartAddr + blockNum * block_szie; //偏移量单位为字节
}
//获得物理地址的盘块号
int getAddrBlock(char* addr)
{
    return (addr - systemStartAddr) / block_szie;
}
//释放盘块、
int releaseBlock(int blockNum, int blockSize)
{
    int endBlock = blockNum + blockSize;
    //修改位示图盘块的位置为0
    for (int i = blockNum; i < endBlock; i++)
        systemStartAddr[i] = '0';
    return 0;
}

dirTable* rootDirTable; //根目录
dirTable* currentDirTable;  //当前所在目录位置
char path[200]; //保存当前绝对路径

//创建FCB
int creatFCB(int fcbBlockNum, int fileBlockNum, int fileSize)
{
    //找到fcb的存储位置
    FCB* currentFCB = (FCB*)getBlockAddr(fcbBlockNum);
    currentFCB->blockNum = fileBlockNum;//文件数据起始位置
    currentFCB->fileSize = fileSize;//文件大小
    currentFCB->link = 1;//文件链接数
    currentFCB->dataSize = 0;//文件已写入数据长度
    currentFCB->readptr = 0;//文件读指针
    return 0;
}
//从目录中查找目录项目
int findUnitInTable(dirTable* myDirTable, char unitName[])
{
    //获得目录表
    int dirUnitAmount = myDirTable->dirUnitAmount;
    int unitIndex = -1;
    for (int i = 0; i < dirUnitAmount; i++)//查找目录项位置
        if (strcmp(unitName, myDirTable->dirs[i].fileName) == 0)
            unitIndex = i;
    return unitIndex;
}
//添加目录项
int addDirUnit(dirTable* myDirTable, char fileName[], int type, int FCBBlockNum)
{
    //获得目录表
    int dirUnitAmount = myDirTable->dirUnitAmount;
    //检测目录表示是否已满
    if (dirUnitAmount == dirTable_max_size)
    {
        printf("dirTables is full, try to delete some file\n");
        return -1;
    }

    //是否存在同名文件
    if (findUnitInTable(myDirTable, fileName) != -1)
    {
        printf("file already exist\n");
        return -1;
    }
    //构建新目录项
    dirUnit* newDirUnit = &myDirTable->dirs[dirUnitAmount];
    myDirTable->dirUnitAmount++;//当前目录表的目录项数量+1
    //设置新目录项内容
    strcpy_s(newDirUnit->fileName, fileName);
    newDirUnit->type = type;
    newDirUnit->startBlock = FCBBlockNum;

    return 0;

}
//创建文件
int creatFile(char fileName[], int fileSize)
{
    //检测文件名字长度
    if(strlen(fileName) >= 59)
    {
        printf("file name too long\n");
        return -1;
    }
    //获得FCB的空间
    int FCBBlock = getBlock(1);
    if(FCBBlock == -1)
        return -1;
    //获取文件数据空间
    int FileBlock = getBlock(fileSize);
    if(FileBlock == -1)
        return -1;
    //创建FCB
    if(creatFCB(FCBBlock, FileBlock, fileSize) == -1)
        return -1;
    //添加到目录项
    if(addDirUnit(currentDirTable, fileName, 1, FCBBlock) == -1)
        return -1;

    return 0;

}

//释放文件内存
int releaseFile(int FCBBlock)
{
    FCB* myFCB = (FCB*)getBlockAddr(FCBBlock);
    myFCB->link--;  //链接数减一
    //无链接,删除文件
    if (myFCB->link == 0)
    {
        //释放文件的数据空间
        releaseBlock(myFCB->blockNum, myFCB->fileSize);
    }
    //释放FCB的空间
    releaseBlock(FCBBlock, 1);
    return 0;
}
//删除目录项
int deleteDirUnit(dirTable* myDirTable, int unitIndex)
{
    //迁移覆盖
    int dirUnitAmount = myDirTable->dirUnitAmount;
    for (int i = unitIndex; i < dirUnitAmount - 1; i++)
    {
        myDirTable->dirs[i] = myDirTable->dirs[i + 1];
    }
    myDirTable->dirUnitAmount--;
    return 0;
}


//删除文件
int deleteFile(char fileName[])
{
    //忽略系统的自动创建的父目录
    if (strcmp(fileName, "..") == 0)
    {
        printf("can't delete ..\n");
        return -1;
    }
    //查找文件的目录项位置
    int unitIndex = findUnitInTable(currentDirTable, fileName);
    if (unitIndex == -1)
    {
        printf("file not found\n");
        return -1;
    }
    dirUnit myUnit = currentDirTable->dirs[unitIndex];
    //判断类型
    if (myUnit.type == 0)//目录
    {
        printf("not a file\n");
        return -1;
    }
    int FCBBlock = myUnit.startBlock;
    //释放内存
    releaseFile(FCBBlock);
    //从目录表中剔除
    deleteDirUnit(currentDirTable, unitIndex);
    return 0;
}

//执行读操作 
int doRead(FCB* myFCB, int length)
{
    //读数据
    int dataSize = myFCB->dataSize;
    char* data = (char*)getBlockAddr(myFCB->blockNum);
    //在不超出数据长度下,读取指定长度的数据
    for (int i = 0; i < length && myFCB->readptr < dataSize; i++, myFCB->readptr++)
    {
        printf("%c", *(data + myFCB->readptr));
    }
    if (myFCB->readptr == dataSize)//读到文件末尾用#表示
        printf("#");
    //换行美观
    printf("\n");
    return 0;
}
//读文件 read
int read(char fileName[], int length)
{
    int unitIndex = findUnitInTable(currentDirTable, fileName);
    if (unitIndex == -1)
    {
        printf("file no found\n");
        return -1;
    }
    //控制块
    int FCBBlock = currentDirTable->dirs[unitIndex].startBlock;
    FCB* myFCB = (FCB*)getBlockAddr(FCBBlock);
    doRead(myFCB, length);
    return 0;
}

//执行写操作
int doWrite(FCB* myFCB, char content[])
{
    int contentLen = strlen(content);
    int fileSize = myFCB->fileSize * block_szie;
    char* data = (char*)getBlockAddr(myFCB->blockNum);
    //在不超出文件的大小的范围内写入
    for (int i = 0; i < contentLen && myFCB->dataSize < fileSize; i++, myFCB->dataSize++)
    {
        *(data + myFCB->dataSize) = content[i];
    }
    if (myFCB->dataSize == fileSize)
        printf("file is full,can't write in\n");
    return 0;
}
//写文件,从末尾写入 write
int write(char fileName[], char content[])
{
    int unitIndex = findUnitInTable(currentDirTable, fileName);
    if (unitIndex == -1)
    {
        printf("file no found\n");
        return -1;
    }
    //控制块
    int FCBBlock = currentDirTable->dirs[unitIndex].startBlock;
    FCB* myFCB = (FCB*)getBlockAddr(FCBBlock);
    doWrite(myFCB, content);
    return 0;
}


//展示当前目录 ls
void showDir()
{
    int unitAmount = currentDirTable->dirUnitAmount;
    printf("total:%d\n", unitAmount);
    printf("name\ttype\tsize\tFCB\tdataStartBlock\n");
    //遍历所有表项
    for (int i = 0; i < unitAmount; i++)
    {
        //获取目录项
        dirUnit unitTemp = currentDirTable->dirs[i];
        printf("%s\t%d\t", unitTemp.fileName, unitTemp.type);
        //该表项是文件,继续输出大小和起始盘块号
        if (unitTemp.type == 1)
        {
            int FCBBlock = unitTemp.startBlock;
            FCB* fileFCB = (FCB*)getBlockAddr(FCBBlock);
            printf("%d\t%d\t%d\n", fileFCB->fileSize, FCBBlock, fileFCB->blockNum);
        }
        else {
            int dirBlock = unitTemp.startBlock;
            dirTable* myTable = (dirTable*)getBlockAddr(dirBlock);
            printf("%d\t%d\n", myTable->dirUnitAmount, unitTemp.startBlock);
        }
    }
}

void interface()
{
    bool inf = 1;
    while (inf)
    {
        cout << "-------------------------------" << endl;
        cout << "----------0、展示当前目录----------" << endl;
        cout << "----------1、创建文件----------" << endl;
        cout << "----------2、读文件-----------" << endl;
        cout << "----------3、写文件----------" << endl;
        cout << "----------4、删除文件----------" << endl;
        cout << "----------5、退出--------------" << endl;
        cout << "-------------------------------" << endl;
        int n;
        cout << "请选择需要执行的指令:";
        cin >> n;
        switch (n)
        {
        case 0: showDir(); break;
        case 1:cout << "请输入文件名:";
            char filename[100];
            cin >> filename;
            creatFile(filename, strlen(filename));
            break;
        case 2:read(filename, strlen(filename)); break;
        case 3:cout << "请输入要写入的内容:";
            char content[100];
            cin >> content;
            write(filename, content);
            break;
        case 4:deleteFile(filename); break;
        case 5:inf = 0; cout << "退出成功!"; break;
        }
    }
}
int main()
{
    initSystem();
    interface();
}

设计内容: (1) 设计一个10个用户的文件系统。每个用户最多可以保存10个文件,一次运行用户可打开多个文件。 (2) 程序采用文件目录。(即设置主目录(MFD)和用户文件目录(UFD))。另外,可打开文件设置指针。 (3) 为了方便实现,对文件的读写作了简化。在执行读写命令时,只需改读写指针。并不进行实际的读写操作。 (4) 实现的基本功能主要包括:改变目录(CD),创建目录(MD),显示目录(DIR),删除目录(RD),打开全部文件(openall),打开单个文件(open),建立一个文件(create),删除一个文件(delete),写文件(write),读文件(read),改文件的保护码(change),退出(exit)等。 要求: 考虑特殊情况如:各个命令对全路径和相对路径的支持、目录不存在时,给出错误信息、不能用cd进入文件、命令之不能有空格(如 ex it,给出错误提示)、相对路径的解析、路径的空格剔除、新建目录文件时的问题、重名问题、目录文件的名字长度限制、目录文件的名字包含不合法字符(注意空格)、删除目录文件时的问题、删除不存在的文件目录给出错误提示、删除目录目录不为空(如果该目录为空,则可删除,否则给出是否做删除提示,删除操作将该目录下的全部文件和子目录删除)、进入到某个目录下,却要删除目录或上级目录、不能用delete删除目录、不能用RD删除文件等都要考虑在内。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值