c++实现的十分简易文件系统

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/little_qi/article/details/73801336

课题作业任务:在内存中开辟一个100M的空间作为磁盘空间,在此上模拟创建一个文件管理系统。

本系统已经实现的相关操作

所有操作都不支持从根目录索引,即都只能访问当前目录下的文件,不能用/a/b越级访问

1)目录相关操作

列出目录下所有文件:ls

切换目录:cd newdir

显示目录:pwd

创建目录:mkdir dirName

删除目录和目录下所有文件:rmdir dirName

修改目录名或文件名:mv oldName newName

 2)文件相关操作

创建文件(大小以1KB为单位):touch filename fileSize

删除文件:rm filename

从上一次后读取size字节的文件内容:read fileName size

从头开始读取size字节的文件内容:reread fileName size

从文件尾写入内容:write fileName content

清空文件,从头写入:rewrite fileName content

 3)系统操作

使用命令帮助:help

退出系统:quit


全部代码大概有600多行,是一个非常简单的实现,不适合想要深入了解的人观看,网上有其他的功能较为强大实现,代码都在上千,比较具有学习的价值。

点击打开链接(很强大,我自己也还没有仔细看)

点击打开链接(代码好像有点问题)

点击打开链接

1. 系统层次结构


系统接口:是该文件系统提供给用户可以使用的命令接口,如ls,mkdir,touch等

文件管理:是系统对于文件和目录层次的管理的,规定了FCB结构,目录结构等,包含了对接口的实现。

磁盘管理:是系统最底层直接对内存空间的管理,如磁盘空闲空间管理,磁盘空间的分配方式等。

2. 磁盘管理

盘块大小:以1KB的空间作为系统盘块,用以分配的基本单位

分配方式:系统采用连续分配的方式,在磁盘上划定要求的连续盘块分配给文件使用

空间管理:系统采用位示图的方法,标记了磁盘上所有盘块的使用情况。

    使用systemStartAddr标记了整个系统的起始地址,以1KB作为盘块划分,所以本系统共有100K个盘块。位示图用char[]表示,所以位示图大小为100KB。位示图存储在系统起始位置,在系统初始化时,0~99号盘块默认被存储位示图使用。

磁盘向文件管理提供的接口说明:

DiskOperate.h

#ifndef DISKOPERATE_H_INCLUDED
#define DISKOPERATE_H_INCLUDED
//磁盘操作接口
#define system_size 100*1024*1024   //系统大小
#define block_szie 1024 //盘块大小
#define block_count system_size/block_szie //系统盘块数目

//初始化系统
void initSystem();
//磁盘分配
int getBlock(int blockSize) ;
//获得盘块的物理地址
char* getBlockAddr(int blockNum);
//获得物理地址的盘块号
int getAddrBlock(char* addr);
//释放盘块、
int releaseBlock(int blockNum, int blockSize);
//退出系统
void exitSystem();
#endif // DISKOPERATE_H_INCLUDED


3.文件层次管理说明

FileOperate.h (部分内容)
//目录项结构:
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];//目录项列表
};
/*
本系统规定一个目录表只占用一个盘块,一个目录项大小为64B,所以一个目录表中最多可含15个目录项,dirUnitAmount记录每个目录表中已含有的目录项数目。系统在初始化时,会自动生成一个空的根目录表存放于磁盘中,作为用户的初始位置,用户所有的目录和文件都这个表为根进行树状目录结构的展开。
当创建一个目录表时,系统会自动为目录表加上一项名为”..”的目录项,指示父目录表的位置。
*/

//FCB结构:
struct FCB {
    int blockNum;   //文件数据起始盘块号
    int fileSize;   //文件大小,盘块为单位
    int dataSize;   //已写入的内容大小,字节为单位
    int readptr;    //读指针,字节为单位
    int link;   //文件链接数
};
/*
	文件控制块包含了文件数据的起始位置和大小。dataSize,readptr是为文件的读写操作而准备的,记录文件已写入的内容长度(不可超过文件大小),和当前读取的位置。Link记录了文件的链接数,用于文件的共享,当文件的链接数为0时,系统可以回收文件的空间。同样的,一个FCB大小为20B,但也用一个盘块保存。
	由于采用的是连续分配方式,所以系统规定文件被创建时,必须给出文件的大小,而且后期也不能修改文件的大小。
*/

看到这里,如果你有修过计算机系统的话,你就会发现我采取了一种最简单的实现方式,都说了十分简易嘛~~

系统用char[]数组作为位示图保存了每一个盘块的使用状态,而且采取了连续分配的方式,对于目录表和FCB都规定直接使用一个盘块,文件又是规定好大小不能扩展的,所以实现起来减少了很多FAT,索引表,那些离散分配所需的连接方式,单纯练手的话,还是十分简易的。

具体实现

1. 磁盘管理的实现

这部分比较简单,代码备注也很详细了,可以直接看代码

DiskOperate.cpp

#include"DiskOperate.h"

#include<stdio.h>
#include<stdlib.h>



char* systemStartAddr;  //系统起始地址

//初始化系统
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;
}


2.文件管理

首先说明全局变量

dirTable* rootDirTable; //根目录
dirTable* currentDirTable;  //当前所在目录位置
char path[200]; //保存当前绝对路径
结构体定义可以见上面文件管理


1)创建文件:touch fileName size

创建文件的过程可以为:

为文件控制块申请空间->为文件数据申请空间->创建FCB控制块->在当前目录添加相关的目录项描述

//创建文件
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;
}
//创建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 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(newDirUnit->fileName, fileName);
    newDirUnit->type = type;
    newDirUnit->startBlock = FCBBlockNum;

    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;
}


2)删除文件:rm fileName

删除文件的流程可以分为:

查找文件在当前目录的目录项描述内容->得到FCB的描述内容->释放FCB空间和文件数据空间->从目录表中删除文件的目录项

(也就是说,在这里其实只是把用户能得到文件的索引删除,而文件的内容在没有被覆盖之前依旧是存在的)

//删除文件
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 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;
}



3)目录的删除和创建

目录的创建和删除与文件的操作大致相同,创建目录时,目录表项的startBlock不是FCB而是指目录的存放位置,而且还要自动为其添加多一个父目录项“..”,用于跳转。删除目录时需要注意是否递归删除目录下的所有文件和目录。详请看最后的完整代码,这里不专门复述。


4)切换目录: cd dirName

cd指令,主要就是让当前目录currentDirTable指向新的目录盘块地址就可以了,目录盘块地址可以在当前目录表的表项中找到。

//切换目录
int changeDir(char dirName[])
{
    //目录项在目录位置
    int unitIndex = findUnitInTable(currentDirTable, dirName);
    //不存在
    if(unitIndex == -1)
    {
        printf("file not found\n");
        return -1;
    }
    if(currentDirTable->dirs[unitIndex].type == 1)
    {
        printf("not a dir\n");
        return -1;
    }
    //修改当前目录
    int dirBlock = currentDirTable->dirs[unitIndex].startBlock;
    currentDirTable = (dirTable*)getBlockAddr(dirBlock);
    //修改全局绝对路径path
    if(strcmp(dirName, "..") == 0)
    {
        //回退绝对路径
        int len = strlen(path);
        for(int i=len-2;i>=0;i--)
            if(path[i] == '\\')
            {
                path[i+1]='\0';
                break;
            }
    }else {
        strcat(path, dirName);
        strcat(path, "\\");
    }

    return 0;
}



5)读文件:read fileName size

主要就是获得文件的初始地址,然后根据需要的读取长度size和当前的读指针进行输出,如果遇到文件尾则输出#,读写的单位都是字节

//读文件 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 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;
}
reread就是先把读指针readptr置为0,然后执行读操作。


6)写文件操作:write fileName content

和读文件差不多,不过是根据当前文件的数据长度,在文件末尾给文件以字节的形式赋值上输入的content内容,数据长度不能超过文件长度

//写文件,从末尾写入 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;
}
//执行写操作
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;
}

7)展示目录下所有文件:ls

对目录表进行遍历,同时根据文件类型做出不同的输出就可以了

//展示当前目录 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);
        }
    }
}


8)FileOperate.cpp

几乎全部的内容都在上面做了阐述了

#include"FileOperate.h"

#include<string.h>
#include<stdio.h>



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


//初始化根目录
void initRootDir()
{
    //分配一个盘块空间给rootDirTable
    int startBlock = getBlock(1);
    if(startBlock == -1)
        return;
    rootDirTable = (dirTable*)getBlockAddr(startBlock);
    rootDirTable->dirUnitAmount = 0;
    //将自身作为父级目录
    //addDirUnit(rootDirTable, "..", 0, startBlock);

    currentDirTable = rootDirTable;
    //初始化初始绝对路径
    path[0]='\\';
    path[1]='\0';
}
//获得绝对路径
char* getPath()
{
    return path;
}
//展示当前目录 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);
        }
    }
}
//切换目录 cd
int changeDir(char dirName[])
{
    //目录项在目录位置
    int unitIndex = findUnitInTable(currentDirTable, dirName);
    //不存在
    if(unitIndex == -1)
    {
        printf("file not found\n");
        return -1;
    }
    if(currentDirTable->dirs[unitIndex].type == 1)
    {
        printf("not a dir\n");
        return -1;
    }
    //修改当前目录
    int dirBlock = currentDirTable->dirs[unitIndex].startBlock;
    currentDirTable = (dirTable*)getBlockAddr(dirBlock);
    //修改全局绝对路径
    if(strcmp(dirName, "..") == 0)
    {
        //回退绝对路径
        int len = strlen(path);
        for(int i=len-2;i>=0;i--)
            if(path[i] == '\\')
            {
                path[i+1]='\0';
                break;
            }
    }else {
        strcat(path, dirName);
        strcat(path, "\\");
    }

    return 0;
}
//修改文件名或者目录名 mv
int changeName(char oldName[], char newName[])
{
    int unitIndex = findUnitInTable(currentDirTable, oldName);
    if(unitIndex == -1)
    {
        printf("file not found\n");
        return -1;
    }
    strcpy(currentDirTable->dirs[unitIndex].fileName, newName);
    return 0;
}


//******************创建和删除文件
//创建文件 touch
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;
}
//创建目录 mkdir
int creatDir(char dirName[])
{
    if(strlen(dirName) >= 59)
    {
        printf("file name too long\n");
        return -1;
    }
    //为目录表分配空间
    int dirBlock = getBlock(1);
    if(dirBlock == -1)
        return -1;
    //将目录作为目录项添加到当前目录
    if(addDirUnit(currentDirTable, dirName, 0, dirBlock) == -1)
        return -1;
    //为新建的目录添加一个到父目录的目录项
    dirTable* newTable = (dirTable*)getBlockAddr(dirBlock);
    newTable->dirUnitAmount = 0;
    char parent[] = "..";
    if(addDirUnit(newTable, parent, 0, getAddrBlock((char*)currentDirTable)) == -1)
        return -1;
    return 0;
}
//创建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 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(newDirUnit->fileName, fileName);
    newDirUnit->type = type;
    newDirUnit->startBlock = FCBBlockNum;

    return 0;
}
//删除文件 rm
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 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;
}
//删除目录 rmdir
int deleteDir(char dirName[])
{
    //忽略系统的自动创建的父目录
    if(strcmp(dirName, "..") == 0)
    {
        printf("can't delete ..\n");
        return -1;
    }
    //查找文件
    int unitIndex = findUnitInTable(currentDirTable, dirName);
    if(unitIndex == -1)
    {
        printf("file not found\n");
        return -1;
    }
    dirUnit myUnit = currentDirTable->dirs[unitIndex];
    //判断类型
    if(myUnit.type == 0)//目录
    {
        deleteFileInTable(currentDirTable, unitIndex);
    }else {
        printf("not a dir\n");
        return -1;
    }
    //从目录表中剔除
    deleteDirUnit(currentDirTable, unitIndex);
    return 0;
}
//删除文件/目录项
int deleteFileInTable(dirTable* myDirTable, int unitIndex)
{
   //查找文件
    dirUnit myUnit = myDirTable->dirs[unitIndex];
    //判断类型
    if(myUnit.type == 0)//目录
    {
        //找到目录位置
        int FCBBlock = myUnit.startBlock;
        dirTable* table = (dirTable*)getBlockAddr(FCBBlock);
        //递归删除目录下的所有文件
        printf("cycle delete dir %s\n", myUnit.fileName);
        int unitCount = table->dirUnitAmount;
        for(int i=1; i<unitCount; i++)//忽略“..”
        {
            printf("delete %s\n", table->dirs[i].fileName);
            deleteFileInTable(table, i);
        }
        //释放目录表空间
        releaseBlock(FCBBlock, 1);
    }else {//文件
        //释放文件内存
        int FCBBlock = myUnit.startBlock;
        releaseFile(FCBBlock);
    }
    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;
}
//重新读文件 reread
int reread(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);
    myFCB->readptr = 0;
    doRead(myFCB, length);

    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;
}
//写文件,从末尾写入 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;
}
//重新写覆盖 rewrite
int rewrite(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);
    //重设数据块
    myFCB->dataSize = 0;
    myFCB->readptr = 0;

    doWrite(myFCB, content);
    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;
}



//从目录中查找目录项目
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;
}


工程代码链接(含有exe可直接运行):FileSystem





没有更多推荐了,返回首页