目录
实验九 设计文件系统
一 实验目的
二 实验内容 1
三 实验过程及结果 2
四 实验总结 9
一 实验目的
(1) 掌握文件系统的工作原理。
(2) 理解文件系统的主要数据结构。
(3) 加深理解文件系统的内部功能和实现方法。
二 实验内容
2.1任务一
编写程序,设计并实现一个单级单用户的文件系统。可以在内存中开辟一
片空间模拟磁盘作为文件系统。文件以块为基本单位,一个块大小为 1024
个字节,共 1024 块。文件系统支持的最大文件数为 1024。
(1) 要求包含以下数据结构:
① 文件分配表 FAT,实现文件的链接分配。表条目指示文件的下一块的
块号。
② 文件控制块 FCB,包含文件名、文件大小、文件首块的块号等属性。
FCB 存储在根目录中。
③ 整个系统的打开文件表。显示当前哪些文件已被打开以及被多少个
进程打开。
(2) 要求提供以下操作:
① 文件系统的初始化:包括对 FAT、根目录和打开文件表的初始化。
② 文件创建/删除命令:create/delete。创建文件时指定如文件名、文件
大小等信息,并为其分配存储空间;删除文件时从根目录找到相应项,
回收其存储空间和 FCB。
③ 文件打开/关闭命令:open/close。打开文件先检查文件是否已打开,
若已打开则计数加 1,否则从根目录中找到相应项,加入打开文件表
中;关闭文件操作类似。
④ 显示目录内容命令:
ls。文件列示时要列出文件名和文件大小等信息。⑤ 进行文件操作时需考虑边界情况:如创建和打开文件时,需要检索是
否存在同名文件;删除文件时,如果文件正在被打开,则不被允许。
(3) 自行编写测试样例,验证文件系统的可靠性。
三 实验过程及结果
3.1编写 C 程序,设计并实现一个单级单用户的文件系统
(1) 要求包含以下数据结构:
①文件分配表 FAT,实现文件的链接分配。表条目指示文件的下一块的
块号。
② 文件控制块 FCB,包含文件名、文件大小、文件首块的块号等属性。
FCB 存储在根目录中。
③ 整个系统的打开文件表。显示当前哪些文件已被打开以及被多少个
进程打开。
(2) 要求提供以下操作:
① 文件系统的初始化:包括对 FAT、根目录和打开文件表的初始化。
② 文件创建/删除命令:create/delete。创建文件时指定如文件名、文件
大小等信息,并为其分配存储空间;删除文件时从根目录找到相应项,
回收其存储空间和 FCB。
文件创建
文件删除
③ 文件打开/关闭命令:open/close。打开文件先检查文件是否已打开,
若已打开则计数加 1,否则从根目录中找到相应项,加入打开文件表
中;关闭文件操作类似。
文件打开
文件关闭
④ 显示目录内容命令:
ls。文件列示时要列出文件名和文件大小等信息。⑤ 进行文件操作时需考虑边界情况:如创建和打开文件时,需要检索是
否存在同名文件;删除文件时,如果文件正在被打开,则不被允许。
- 功能测试
文件的创建与删除
打开文件与关闭
边界测试
①同名文件
②删除打开的文件
退出文件系统
附录展示完整代码.
四 实验总结
通过本次实验,成功设计并实现了一个单级单用户的文件系统,主要包括文件分配表(FAT)、文件控制块(FCB)和打开文件表等数据结构的定义。文件系统的初始化、文件的创建与删除、文件的打开与关闭、目录内容的显示等操作均得以实现。通过编写测试样例,能够测试该文件系统的可靠性,充分考虑并且处理了边界情况,如同名文件的处理、删除打开的文件等。通过这个过程深入地理解了文件系统的内部结构和实现方法,包括文件的链接分配、根目录的管理以及打开文件的处理。
本次实验加深了对文件系统的工作原理,还加深了对操作系统内部功能和实现方法的认识。利用C语言的数据结构和文件操作相关的知识,提高了编程和问题解决的能力。通过不断调试和优化,成功地完成了一个可靠的文件系统,并通过测试验证了其稳定性和正确性。
附录
附录 |
算法详细代码 |
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #define BLOCK_SIZE 1024
- #define MAX_BLOCKS 1024
- #define MAX_FILES 1024
- #define MAX_FILENAME_LEN 50
- // 文件分配表 FAT
- typedef struct {
- int nextBlock;
- } FATEntry;
- // 文件控制块 FCB
- typedef struct {
- char filename[MAX_FILENAME_LEN];
- int size;
- int firstBlock;
- } FCBEntry;
- // 打开文件表
- typedef struct {
- char filename[MAX_FILENAME_LEN];
- int openCount;
- } OpenFileEntry;
- // 文件系统
- typedef struct {
- FATEntry fat[MAX_BLOCKS];
- FCBEntry rootDir[MAX_FILES];
- OpenFileEntry openFiles[MAX_FILES];
- } FileSystem;
- FileSystem fs;
- // 初始化文件系统
- void initFileSystem() {
- for (int i = 0; i < MAX_BLOCKS; i++) {
- fs.fat[i].nextBlock = -1;
- }
- for (int i = 0; i < MAX_FILES; i++) {
- strcpy(fs.rootDir[i].filename, "");
- fs.rootDir[i].size = 0;
- fs.rootDir[i].firstBlock = -1;
- strcpy(fs.openFiles[i].filename, "");
- fs.openFiles[i].openCount = 0;
- }
- }
- // 创建文件
- void createFile(char* filename, int size) {
- // 检查是否存在同名文件
- for (int i = 0; i < MAX_FILES; i++) {
- if (strcmp(fs.rootDir[i].filename, filename) == 0) {
- printf("已存在同名文件。\n");
- return;
- }
- }
- // 寻找空闲的文件控制块
- int fcbIndex = -1;
- for (int i = 0; i < MAX_FILES; i++) {
- if (strlen(fs.rootDir[i].filename) == 0) {
- fcbIndex = i;
- break;
- }
- }
- if (fcbIndex == -1) {
- printf("文件系统已满,无法创建更多文件。\n");
- return;
- }
- // 寻找空闲的块
- int blockIndex = -1;
- for (int i = 0; i < MAX_BLOCKS; i++) {
- if (fs.fat[i].nextBlock == -1) {
- blockIndex = i;
- break;
- }
- }
- if (blockIndex == -1) {
- printf("文件系统已满,无法分配更多块。\n");
- return;
- }
- // 设置文件控制块和文件分配表
- strcpy(fs.rootDir[fcbIndex].filename, filename);
- fs.rootDir[fcbIndex].size = size;
- fs.rootDir[fcbIndex].firstBlock = blockIndex;
- // 计算需要分配的块数
- int numBlocks = (size + BLOCK_SIZE - 1) / BLOCK_SIZE;
- // 分配文件的块
- for (int i = 0; i < numBlocks; i++) {
- int nextBlockIndex = -1;
- for (int j = blockIndex + 1; j < MAX_BLOCKS; j++) {
- if (fs.fat[j].nextBlock == -1) {
- nextBlockIndex = j;
- break;
- }
- }
- if (nextBlockIndex == -1) {
- printf("文件系统已满,无法分配更多块。\n");
- return;
- }
- fs.fat[blockIndex].nextBlock = nextBlockIndex;
- blockIndex = nextBlockIndex;
- }
- fs.fat[blockIndex].nextBlock = -1; // 文件结束标志
- printf("文件创建成功。\n");
- }
- // 删除文件
- void deleteFile(char* filename) {
- // 查找文件
- int fcbIndex = -1;
- for (int i = 0; i < MAX_FILES; i++) {
- if (strcmp(fs.rootDir[i].filename, filename) == 0) {
- fcbIndex = i;
- break;
- }
- }
- if (fcbIndex == -1) {
- printf("未找到文件。\n");
- return;
- }
- // 检查文件是否正在被打开
- for (int i = 0; i < MAX_FILES; i++) {
- if (strcmp(fs.openFiles[i].filename, filename) == 0) {
- printf("文件正在被打开,无法删除。\n");
- return;
- }
- }
- // 回收文件占用的块
- int currentBlock = fs.rootDir[fcbIndex].firstBlock;
- int nextBlock;
- while (currentBlock != -1) {
- nextBlock = fs.fat[currentBlock].nextBlock;
- fs.fat[currentBlock].nextBlock = -1;
- currentBlock = nextBlock;
- }
- // 清空文件控制块
- strcpy(fs.rootDir[fcbIndex].filename, "");
- fs.rootDir[fcbIndex].size = 0;
- fs.rootDir[fcbIndex].firstBlock = -1;
- printf("文件删除成功。\n");
- }
- // 打开文件
- void openFile(char* filename) {
- // 查找文件
- int fcbIndex = -1;
- for (int i = 0; i < MAX_FILES; i++) {
- if (strcmp(fs.rootDir[i].filename, filename) == 0) {
- fcbIndex = i;
- break;
- }
- }
- if (fcbIndex == -1) {
- printf("未找到文件。\n");
- return;
- }
- // 检查文件是否已经打开
- for (int i = 0; i < MAX_FILES; i++) {
- if (strcmp(fs.openFiles[i].filename, filename) == 0) {
- fs.openFiles[i].openCount++;
- printf("文件打开成功,打开次数:%d\n", fs.openFiles[i].openCount);
- return;
- }
- }
- // 寻找空闲的打开文件表项
- int openFileIndex = -1;
- for (int i = 0; i < MAX_FILES; i++) {
- if (strlen(fs.openFiles[i].filename) == 0) {
- openFileIndex = i;
- break;
- }
- }
- if (openFileIndex == -1) {
- printf("打开的文件过多,无法再打开更多文件。\n");
- return;
- }
- // 添加文件到打开文件表
- strcpy(fs.openFiles[openFileIndex].filename, filename);
- fs.openFiles[openFileIndex].openCount = 1;
- printf("文件打开成功,打开次数:1\n");
- }
- // 关闭文件
- void closeFile(char* filename) {
- // 查找文件在打开文件表中的位置
- int openFileIndex = -1;
- for (int i = 0; i < MAX_FILES; i++) {
- if (strcmp(fs.openFiles[i].filename, filename) == 0) {
- openFileIndex = i;
- break;
- }
- }
- if (openFileIndex == -1) {
- printf("文件未打开。\n");
- return;
- }
- // 减少文件的打开计数
- fs.openFiles[openFileIndex].openCount--;
- // 如果计数为 0,则从打开文件表中移除
- if (fs.openFiles[openFileIndex].openCount == 0) {
- strcpy(fs.openFiles[openFileIndex].filename, "");
- }
- printf("文件关闭成功。\n");
- }
- // 显示目录内容
- void listDirectory() {
- printf("目录内容:\n");
- for (int i = 0; i < MAX_FILES; i++) {
- if (strlen(fs.rootDir[i].filename) > 0) {
- printf("文件: %s, 大小: %d, 文件首块: %d\n",
- fs.rootDir[i].filename, fs.rootDir[i].size, fs.rootDir[i].firstBlock);
- }
- }
- }
- int main() {
- char command[100]; // 为了容纳整个命令,可以根据实际情况调整大小
- char filename[MAX_FILENAME_LEN];
- int size;
- initFileSystem();
- while (1) {
- printf("Laix7&filesystem >");
- scanf(" %[^\n]", command);
- // 使用 sscanf 解析命令
- char action[10];
- if (sscanf(command, "%s", action) == 1) {
- if (strcmp(action, "create") == 0) {
- if (sscanf(command, "%*s %s %d", filename, &size) == 2) {
- createFile(filename, size);
- } else {
- printf("错误命令格式!请重新输入\n");
- }
- } else if (strcmp(action, "delete") == 0) {
- if (sscanf(command, "%*s %s", filename) == 1) {
- deleteFile(filename);
- } else {
- printf("错误命令格式!请重新输入\n");
- }
- } else if (strcmp(action, "open") == 0) {
- if (sscanf(command, "%*s %s", filename) == 1) {
- openFile(filename);
- } else {
- printf("错误命令格式!请重新输入\n");
- }
- } else if (strcmp(action, "close") == 0) {
- if (sscanf(command, "%*s %s", filename) == 1) {
- closeFile(filename);
- } else {
- printf("错误命令格式!请重新输入\n");
- }
- } else if (strcmp(action, "ls") == 0) {
- listDirectory();
- } else if (strcmp(action, "exit") == 0) {
- printf("退出文件系统...\n");
- break;
- } else {
- printf("错误命令格式!请重新输入\n");
- }
- } else {
- printf("错误命令格式!请重新输入\n");
- }
- }
- return 0;
- }
|