一.实验目的:
通过编写一个简单的文件管理程序,实现主要的文件操作命令,加深操作系统对于文件目录管理方式的理解。应用文件管理的相关命令完成下列操作:建立文件、建立文件夹、复制文件及文件夹、移动文件及文件夹、删除文件及文件夹、显示文件夹中的内容、查看文件内容、修改文件权限、搜索文件等。
采用二级目录实现文件管理
二.实验环境
硬件环境:计算机一台,局域网环境;
软件环境: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();
}