#include <windows.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stdio.h> // 添加文件操作相关头文件
using namespace std;
#include <vector>
#include <string>
// 目录项结构定义
struct DirectoryEntry {
std::string filename;
int cluster;
// 其他需要的字段...
};
class Directory {
private:
std::vector<DirectoryEntry> entries;
int maxFileCount; // 可选:如果需要限制最大文件数
public:
Directory(int maxCount = 100) : maxFileCount(maxCount) {
entries.reserve(maxCount); // 预分配空间
}
// 添加目录项
bool addEntry(const DirectoryEntry& entry) {
if (entries.size() >= maxFileCount) {
return false; // 目录已满
}
entries.push_back(entry);
return true;
}
};
#define FILENAME_LEN 3 // 文件名长度
#define SHELL_LEN 5 // 命令动词长度
#define ShellCount 6 // 命令种类
char *path = "disk.txt"; // 保存磁盘文件
char *shellstr[ShellCount] = {"dir", "cre", "del", "dis", "fat", "exit"};
// 文件目录结构:文件名3B,文件属性1B,长度2B,起始簇号2B
#define HPC 4 // 每柱面磁道数
#define SPT 16 // 每磁道的扇区数
#define Cylinders 64 // 柱面数
#define SectorSize 128 // 扇区大小
#define DirSize 16 // 根目录大小(扇区),占16扇区
int Maxfilecount = DirSize * SectorSize / 8; // 存放的最大文件数
// FAT表占用的扇区数和开始扇区号
int FatSize = ((HPC * SPT * Cylinders * 2) % SectorSize == 0)? (HPC * SPT * Cylinders * 2) / SectorSize : (HPC * SPT * Cylinders * 2) / SectorSize + 1;
int FatBegin = DirSize;
// 位示图占用的扇区数和开始扇区号
int BitMapSize = ((HPC * SPT * Cylinders / 8) % SectorSize == 0)? (HPC * SPT * Cylinders / 8) / SectorSize : (HPC * SPT * Cylinders / 8) / SectorSize + 1;
int BitMapBegin = DirSize + FatSize;
int DataBeginSector = DirSize + FatSize + BitMapSize; // 存放数据起始扇区号
unsigned short Memory = 0; // 空闲盘块数
unsigned char DISK[Cylinders][HPC][SPT][SectorSize]; // 磁盘大小
unsigned short FAT[HPC * SPT * Cylinders]; // 内存FAT表
unsigned short bitmap[HPC * SPT * Cylinders / 16]; // 内存位示图
unsigned char Dir[DirSize * SectorSize]; // 内存目录
unsigned char filecon[1024]; // 文件内容
// 目录项结构定义
typedef struct {
unsigned char name[3]; // 文件名
unsigned char attr; // 文件属性
unsigned short length; // 长度
unsigned short first_cluster; // 起始簇号
} DirectoryEntry;
// 功能:错误命令处理
// id:错误代码
void errorp(int id) { // 错误命令处理函数
switch (id) {
case 0:
puts("文件不存在!");
break;
case 1:
puts("文件/目录已存在!");
break;
case 2:
puts("语法不正确!");
break;
case 3:
puts("不存在命令!");
break;
case 4:
puts("存储空间不够!");
break;
case 5:
puts("文件名太长!");
break;
case 6:
puts("无空闲目录!");
break;
case 7:
puts("操作命令太长!");
break;
default:
puts("无效命令!");
}
}
// 功能:如果位示图第n位为1则返回真,为0返回假
bool getbitmap(int n) {
return bool(bitmap[n / 16] & (1 << (n % 16)));
}
// 功能:初始化位示图和FAT
void initbitmap() {
int i;
int k1 = HPC * SPT * Cylinders - DataBeginSector;
int k2 = (k1 % 16 == 0)? k1 / 16 : k1 / 16 + 1;
for (i = 0; i < k2; i++)
bitmap[i] = (rand() * 3) % 65536;
for (i = 0; i < k1; i++)
if (getbitmap(i) == 0) {
Memory++;
FAT[i] = 0;
}
else
FAT[i] = -1;
}
// 功能:显示位示图
void showbitmap() {
int i;
// int k=HPC*SPT*Cylinders-DataBeginSector;//显示全部位图
int k = 128; // 显示部分位图
cout << "位示图:" << endl;
for (i = 0; i < k; i++) {
printf("%d ", bool(bitmap[i / 16] & (1 << (i % 16))));
if (i % 16 == 15) cout << endl;
}
cout << endl;
}
// 功能:显示FAT
void showfat() {
int i;
// int k=HPC*SPT*Cylinders;//显示全部FAT
int k = 128; // 显示部分FAT
cout << "FAT表:" << endl;
for (i = 0; i < k; i++) {
printf("%-8d", FAT[i]);
if (i % 8 == 7) cout << endl;
}
cout << endl;
}
// 功能:将位示图中的第n位设成k状态
void setbitmap(int n, int k) {
if (k)
bitmap[n / 16] = bitmap[n / 16] | (1 << (n % 16));
else
bitmap[n / 16] = bitmap[n / 16] & ~(1 << (n % 16));
}
// 功能:从内存Dir[]开始查找str目录结点并返回str节点指针,如没查到则返回NULL。
// str:文件名
unsigned char *find(char *str) {
unsigned char *p = (unsigned char *)directory;
bool mark;
unsigned short j;
if (str[0] == '\0') return NULL;
for (int i = 0; i < Maxfilecount; i++) {
if (*p != '\0') { // 目录不空对比
mark = true;
for (j = 0; j < strlen(str); j++) {
if (*(str + j) != *(p + j)) {
mark = false;
break;
}
}
if ((mark == true && j == FILENAME_LEN) || (mark == true && j < FILENAME_LEN && *(p + j) == '\0'))
return p;
}
p += sizeof(DirectoryEntry);
}
return NULL;
}
// 功能:将p后的长度为SectorSize字符串写到ls扇区中
// 如果字符串长度小于SectorSize,则写实际长度
void writedisk(unsigned char *p, int ls) {
int C, H, S;
C = ls / (HPC * SPT); // 计算柱面号
H = (ls / SPT) % HPC; // 计算磁头号
S = ls % SPT; // 计算扇区号
int realSize = strlen((char *)p) < SectorSize? strlen((char *)p) : SectorSize;
for (int i = 0; i < realSize; i++) {
DISK[C][H][S][i] = *(p + i);
}
if (realSize < SectorSize) {
for (int i = realSize; i < SectorSize; i++) {
DISK[C][H][S][i] = '\0';
}
}
}
// 功能:将ls扇区中长度为size的字符串读到字符型指针p中
void readdisk(unsigned char *p, int ls, int size) {
int C, H, S;
C = ls / (HPC * SPT); // 计算柱面号
H = (ls / SPT) % HPC; // 计算磁头号
S = ls % SPT; // 计算扇区号
for (int i = 0; i < size; i++)
*(p + i) = DISK[C][H][S][i];
}
// 查找空闲簇
unsigned short find_free_cluster() {
// 跳过簇0和簇1(保留簇)
for (unsigned short i = 2; i < HPC * SPT * Cylinders; i++) {
if (FAT[i] == 0) { // 0表示空闲簇
return i;
}
}
return 0; // 没有可用簇
}
// 初始化程序
void init() {
int i = 0;
FILE *fp1;
unsigned char *tmp = &DISK[0][0][0][0];
fp1 = fopen(path, "rb");
if (fp1 == NULL) // 第一次运行该程序
initbitmap();
else {
while (!feof(fp1)) {
*(tmp + i) = fgetc(fp1);
i++;
}
fclose(fp1);
// 将磁盘根目录读到Dir[]中,便于操作
unsigned char *p = Dir;
for (i = 0; i < DirSize; i++) {
readdisk(p, i, SectorSize);
p += SectorSize;
}
// 将FAT表读入内存FAT[]中
unsigned short *p1 = FAT;
for (i = 0; i < FatSize; i++) {
readdisk((unsigned char *)p1, i + FatBegin, SectorSize);
p1 += SectorSize / 2;
}
// 将bitmap表读入内存bitmap[]中
p1 = bitmap;
for (i = 0; i < BitMapSize; i++) {
readdisk((unsigned char *)p1, i + BitMapBegin, SectorSize);
p1 += SectorSize / 2;
}
int k1 = HPC * SPT * Cylinders - DataBeginSector;
for (i = 0; i < k1; i++)
if (getbitmap(i) == 0)
Memory++;
}
}
// 程序运行完后保存磁盘DISK到文件中
void save() {
int i = 0;
FILE *fp1;
// 将内存Dir[]写到DISK中,然后用文件的方式保存
unsigned char *p = Dir;
for (i = 0; i < DirSize; i++) {
writedisk(p, i);
p += SectorSize;
}
// 将内存FAT[]表写入DISK中
unsigned short *p1 = FAT;
for (i = 0; i < FatSize; i++) {
writedisk((unsigned char *)p1, i + FatBegin);
p1 += SectorSize / 2;
}
// 将内存bitmap[]写到DISK中
p1 = bitmap;
for (i = 0; i < BitMapSize; i++) {
writedisk((unsigned char *)p1, i + BitMapBegin);
p1 += SectorSize / 2;
}
// 将DISK保存在磁盘文件中
unsigned char *tmp = &DISK[0][0][0][0];
fp1 = fopen(path, "wb");
if (fp1 == NULL)
cout << "无法写入文件!";
else {
for (i = 0; i < Cylinders * HPC * SPT * SectorSize; i++)
fputc(*(tmp + i), fp1);
fclose(fp1);
}
}
// 功能:显示str目录内容
// str:可以采用绝对或相对路径
bool direxc(char *str) {
int i, j;
char *dirstr[2] = { "<file>", "<dir>" };
// showbitmap();
unsigned char *p = (unsigned char *)directory;
char filename[4];
unsigned short length, start;
cout << "文件名 类型 长度 起始块号" << endl;
for (i = 0; i < Maxfilecount; i++) {
if (*p != '\0') { // 目录不空显示
for (j = 0; j < 3; j++)
filename[j] = *(p + j);
filename[j] = '\0';
length = ((DirectoryEntry *)p)->length;
start = ((DirectoryEntry *)p)->first_cluster;
printf("%6s %6s %5u%5u\n", filename, dirstr[((DirectoryEntry *)p)->attr], length, start);
}
p += sizeof(DirectoryEntry);
}
printf("磁盘剩余空间为:%d字节 \n", Memory * SectorSize);
return true;
}
// 自动生成文件内容,并返回文件长度
int createcon(unsigned char *con) {
int i;
while (1) {
printf("请输入创建文件长度(1025B以下):");
scanf("%d", &i);
if (i > 0 && i < 1025) break;
fflush(stdin);
}
for (int k = 0; k < i; k++, con++) *con = 32 + rand() % 95;
*con = '\0';
return i;
}
// 查找第一个空白目录
unsigned char *findfirstemptyDir() {
unsigned char *p = (unsigned char *)directory;
for (int i = 0; i < Maxfilecount; i++)
if (*p == '\0')
return p;
else
p += sizeof(DirectoryEntry);
return NULL;
}
// 功能:将文件名写到目录中,最多3个字符,
// 如果文件名少于3个字符,则后面加'\0'
// p:目录开始指针,file:文件名指针
void writefilename(unsigned char *p, char *file) {
unsigned short i, k;
k = strlen(file);
for (i = 0; i < k; i++) {
*p = (unsigned char)*file;
p++;
file++;
}
if (k < 3)
*p = '\0';
}
// 功能:创建str文件
// 流程:分配块,写数据,更新fat表。
// str:可以采用绝对或相对路径
bool creexc(char *str) {
unsigned short i, j, k;
short l;
int length;
unsigned char *tmp = find(str);
unsigned char *p = filecon;
if (tmp != NULL) // 文件已经存在
{
errorp(1);
return false;
}
else
{
// 1. 查找空闲目录项
for (i = 0; i < Maxfilecount; i++) {
if (((DirectoryEntry *)&directory[i])->name[0] == 0x00) { // 找到空闲目录项
break;
}
}
if (i == Maxfilecount) { // 没有空闲目录项
errorp(6);
return false;
}
// 2. 生成文件内容
length = createcon(filecon);
if (length <= 0) {
errorp(6); // 文件长度错误
return false;
}
// 3. 分配磁盘块并写入数据
unsigned short first_cluster = 0;
unsigned short current_cluster = 0;
unsigned short next_cluster = 0;
int bytes_written = 0;
// 分配第一个簇
first_cluster = find_free_cluster();
if (first_cluster == 0) {
errorp(4); // 磁盘空间不足错误
return false;
}
current_cluster = first_cluster;
// 写入数据到磁盘块
while (bytes_written < length) {
// 计算当前簇能写入的字节数(每簇4字节)
int bytes_to_write = (length - bytes_written > 4)? 4 : length - bytes_written;
// 写入数据到磁盘块
unsigned char buffer[4];
memcpy(buffer, &filecon[bytes_written], bytes_to_write);
writedisk(buffer, current_cluster);
bytes_written += bytes_to_write;
// 如果还有数据需要写入,分配下一个簇
if (bytes_written < length) {
next_cluster = find_free_cluster();
if (next_cluster == 0) {
// 回滚已分配的簇
while (current_cluster != first_cluster) {
unsigned short prev_cluster = current_cluster;
current_cluster = find_prev_cluster(prev_cluster);
FAT[prev_cluster] = 0; // 释放簇
Memory++;
}
FAT[first_cluster] = 0; // 释放第一个簇
Memory++;
errorp(4); // 磁盘空间不足错误
return false;
}
// 更新FAT表,链接到下一个簇
FAT[current_cluster] = next_cluster;
current_cluster = next_cluster;
}
}
// 标记最后一个簇为文件结束
FAT[current_cluster] = 0xFFFF; // 表示文件结束
// 4. 更新目录项
DirectoryEntry *dir_entry = &directory[i];
memcpy(dir_entry->name, str, 3);
dir_entry->attr = 0; // 普通文件
dir_entry->length = length;
dir_entry->first_cluster = first_cluster;
// 5. 保存更新后的目录和FAT表到磁盘
save();
printf("文件创建成功,大小: %d 字节\n", length);
return true;
}
return true;
}
// 查找前一个簇(用于回滚操作)
unsigned short find_prev_cluster(unsigned short cluster) {
for (unsigned short i = 2; i < HPC * SPT * Cylinders; i++) {
if (FAT[i] == cluster) {
return i;
}
}
return 0; // 没有找到前一个簇
}
// 功能:删除文件或目录
// 释放磁盘块,清空目录项
// str:文件名
void delexc(char *str) {
unsigned char *tp = find(str);
if (tp != NULL) {
// 1. 找到文件在目录中的索引
int dir_index = (tp - (unsigned char *)directory) / sizeof(DirectoryEntry);
// 2. 获取文件的第一个簇
unsigned short current_cluster = directory[dir_index].first_cluster;
// 3. 释放文件占用的所有簇
while (current_cluster != 0xFFFF && current_cluster != 0) {
unsigned short next_cluster = FAT[current_cluster];
FAT[current_cluster] = 0; // 释放簇
Memory++; // 增加空闲空间计数
current_cluster = next_cluster;
}
// 4. 清空目录项
memset(&directory[dir_index], 0, sizeof(DirectoryEntry));
// 5. 保存更新后的目录和FAT表
save();
printf("文件删除成功\n");
}
else
errorp(0);
}
// 功能:显示文件内容
// str:文件名
void disexc(char *str) {
unsigned char *tp = find(str);
if (tp != NULL) {
// 1. 找到文件在目录中的索引
int dir_index = (tp - (unsigned char *)directory) / sizeof(DirectoryEntry);
// 2. 获取文件信息
unsigned short current_cluster = directory[dir_index].first_cluster;
unsigned short file_size = directory[dir_index].length;
// 3. 读取文件内容
int bytes_read = 0;
unsigned char *p = filecon;
memset(filecon, 0, sizeof(filecon)); // 清空文件内容缓冲区
while (current_cluster != 0xFFFF && current_cluster != 0 && bytes_read < file_size) {
// 计算当前簇要读取的字节数
int bytes_to_read = (file_size - bytes_read > 4)? 4 : file_size - bytes_read;
// 从磁盘读取数据
unsigned char buffer[4];
readdisk(buffer, current_cluster, bytes_to_read);
memcpy(p, buffer, bytes_to_read);
p += bytes_to_read;
bytes_read += bytes_to_read;
// 获取下一个簇
current_cluster = FAT[current_cluster];
}
*p = '\0'; // 添加字符串结束符
cout << filecon << endl;
}
else
errorp(0);
}
// 功能:显示部分FAT和位示图内容
// str:文件名
void fatexc() {
showbitmap();
showfat();
}
void menu() { // 显示命令菜单
printf("有下列命令可供使用:\n");
printf("[1] dir 显示目录内容\n");
printf("[2] cre 新建文件\n");
printf("[3] del 删除文件\n");
printf("[4] dis 显示文件内容\n");
printf("[5] fat 显示部分FAT及位示图\n");
printf("[6] exit 退出系统\n");
}
// 功能:解释命令。根据不同的输入转到不同的函数执行
// str:键盘输入串
bool shell(char *str) {
int re = -1, i = 0, cmdp = 0, filep = 0;
char *p = str;
char cmdstr[SHELL_LEN] = "";
char filestr[10] = "";
// 以下程序完成命令和参数的分解分别放到cmdstr,filestr数组中
while (*p == ' ') // 删除字符串前面空格
p++;
int firstspace = 0; // 第一个空格
while (1) {
if (*p == '\0')
break;
if (*p == ' ') {
firstspace = 1;
p++;
}
else {
if (firstspace == 0) {
cmdstr[cmdp++] = *p++;
if (cmdp >= 5) {
errorp(7);
return false;
}
}
else {
filestr[filep++] = *p++;
if (filep >= 4) {
errorp(5);
return false;
}
}
}
}
filestr[filep] = '\0';
cmdstr[cmdp] = '\0';
for (i = 0; i < ShellCount; i++)
if (strcmp(cmdstr, shellstr[i]) == 0) {
re = i;
break;
}
switch (re) { // 根据解释的命令执行对应的操作
case 0:
direxc(filestr);
break;
case 1:
if (strlen(filestr) == 0) {
errorp(2);
return false;
}
creexc(filestr);
break;
case 2:
if (strlen(filestr) == 0) {
errorp(2);
return false;
}
delexc(filestr);
break;
case 3:
if (strlen(filestr) == 0) {
errorp(2);
return false;
}
disexc(filestr);
break;
case 4:
fatexc();
break;
case 5:
save();
exit(0);
break;
default:
errorp(8);
break;
}
return true;
}
int main() {
char inputs[256] = "";
srand((unsigned)time(0)); // 每次产生不一样的随机数
init();
menu();
while (1) {
printf("\n>");
gets(inputs);
shell(inputs);
menu();
}
}
修改代码使之运行正确