C/C++模拟操作系统文件操作

效果图

这里写图片描述

基本要求

利用磁盘文件实现操作系统的文件管理功能,主要包括目录结构的管理、外存空间的分配与释放以及空闲空间管理三部分。

实验提示

  1. 通过初始化操作建立一个模拟外存空间的虚拟磁盘文件,在该文件中保存目录和文件内容。创建该文件时应创建初始的根目录内容、文件分配表。根目录实为一特殊文件,其开始内容为空,大小为一个块。
  2. 文件目录项(可以采用FCB格式)应包括类型(目录 or文件)、创建日期、大小、第一个磁盘块块号。
  3. 显示命令提示符“$”,并根据输入命令完成相应的文件操作:
    • MD(创建子目录):创建目录文件,并在父目录文件中增加目录项。
    • CD(切换工作目录):根据当前目录切换到指定目录。
    • RD(删除子目录):搜索所要删除的目录是否为空目录,若是则删除。
    • MK(创建空文件):创建指定大小的文件(如输入命令 “mk test 2000”,表示创建大小为2000字节的test文件),并在父目录中添加文件名称;还应对FAT表进行适当修改。
    • DIR:列出当前目录的所有目录项。
    • FORMAT:根据进一步的虚拟磁盘文件名和块个数信息创建出虚拟磁盘文件。

代码

首先是基本DOS命令函数头文件.< < DOS.h > >

#ifndef DOS_H_INCLUDED
#define DOS_H_INCLUDED
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
#include <ctime>
#include <cstdlib>
#include <cmath>

#define LAST_BLOCK 0xFFFF//fat16
#define EMPTY_BLOCK 0x0000
#define BLOCK_SIZE 1024
#define BEEP 7


using namespace std;

typedef struct FCB{
    char name[8];//文件或者目录名
    int size;//文件或者目录字节数
    int first_block;//第一个块号
    char dateTime[15];//日期时间
    char type;//1.文件 2.目录 0.空闲
}FCB;


string current_directory = "";
string format_file_name = "";
int current_directory_block_no = 0;//当前目录块号

namespace DOS {
    void alert(char str[]) {
        cout<<str<<endl;
    }

    bool is_all_digits(string &str) {//判断是否为全数字
        for(int i = 0; i < str.length(); i++) {
            if(str[i] < '0' || str[i] > '9') {
                return false;
            }
        }
        return true;
    }

    int to_integer (string &str) {//字符串转化为数字
        if(is_all_digits(str)) {
            return atoi(str.c_str());
        }
        return -1;
    }

    bool is_power_of_two(int i) {//判断是否为2的整数次幂
        if(i % 2 != 0) {
            return false;
        } else {
            while(i != 1) {
                if(i%2 != 0) {
                    return false;
                }
                i = i/2;
            }
        }
        return true;
    }

    void trim (char *str) {//去掉前后空格
        char *p = str;
        while(*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
            p++;
        }
        strcmp(str, p);
        int i = strlen(str)-1;
        while(str[i] == ' ' || str[i] == '\t' || str[i] == '\r' || str[i] == '\n') {
            i--;
        }
        str[i+1] = '\0';
    }

    void toUpperCase (string &str) {
        transform(str.begin(), str.end(), str.begin(), ::toupper);
    }

    void toLowerCase (string &str) {
        transform(str.begin(), str.end(), str.begin(), ::tolower);
    }

    int split (string &str,string ss[10],char ch) {//分割字符串
        int i = 0, j = 0, k = 0;
        while(str[i] == ch) {
            i++;
        }
//       if(str[i] == 0) {
//           return 0;
//      }
        char a[10][40];
        int index = 0;
        for(;i < str.length(); i++) {
            if(str[i] != ch) {
                a[j][k++] = str[i];
            }else {
                a[j][k] = '\0';
                if(k != 0) {
                   ss[index] = a[j];
                   index++;
                }
                j++;
                k = 0;
            }
        }
        a[j][k] = '\0';
        if(k != 0) {
            ss[index] = a[j];
            index++;
        }
        return index;
    }

    void setDateTime(char dateTime[]) {
        time_t ticks = time(NULL);
        struct tm *t = localtime(&ticks);
        strftime(dateTime, 16, "%Y%m%d %H%M%S", t);
    }

    int get_block_count() {//获取块大小
        ifstream in (format_file_name.c_str(), ios::in|ios::binary|ios::ate);
        long size = in.tellg();
        in.close();
        return size/(BLOCK_SIZE+2);
    }

    int get_file_size(string &str) {//获取文件大小
        ifstream in (str.c_str(), ios::in|ios::binary|ios::ate);
        long size = in.tellg();
        in.close();
        return size;
    }

    void read_fat(char *c) {
        ifstream in (format_file_name.c_str(), ios::in|ios::binary);
        if(!in.is_open()) {
            alert("Failed to create file!!");
            return;
        }
        int length = get_block_count();
        in.read(c, 2*length);
        in.close();
    }

    void write_fat(char *c) {
        FILE *fp = fopen(format_file_name.c_str(), "rb+");
        if(fp == NULL) return;
        fwrite( c, 2*get_block_count(), 1, fp);
        fclose(fp);
    }

    void read_block(int block_no, char *str) {
        ifstream in (format_file_name.c_str(), ios::in|ios::binary);
        if(!in.is_open()) {
            alert("Failed to create file!!");
            return;
        }
        in.seekg((get_block_count()*2 + block_no*BLOCK_SIZE),ios::beg);
        in.read(str, BLOCK_SIZE);
        in.close();

    }

    void write_block(int block_no, char *str) {
        FILE *fp = fopen(format_file_name.c_str(), "rb+");
        if(fp == NULL) {
            return;
        }
        int i = get_block_count()*2 + block_no*BLOCK_SIZE;
        fseek(fp, i, 0);
        fwrite(str, BLOCK_SIZE,1,fp);
        fclose(fp);
    }

    int get_empty_block_num(int start) {//start开始以后后面第一个空闲块号
        char *fat;
        unsigned short *tmp;
        int blockNum = -1;
        int i, length;
        length = get_block_count();
        fat = new char [get_block_count()*2];
        read_fat(fat);
        tmp = (unsigned short*)fat;
        for(i = 0; i < start; i++, tmp++);
        for(; i < length; i++, tmp++) {
            //cout<<(short *)*tmp<<endl;
            if( *tmp == EMPTY_BLOCK) {
                blockNum = i;
                break;
            }
        }
        delete[] fat;
        //cout<<blockNum<<endl;
        return blockNum;

    }

    void set_fat_item(int idx, unsigned short c) {//设置FAT表第idx项为c
        char *fat, *tmp;
        unsigned short *shortPnt;
        fat = new char [get_block_count()*2];
        read_fat(fat);
        shortPnt=(unsigned short*)fat;
        *(shortPnt+idx) = c;
        //printf("%4x%d",c,idx);
        write_fat(fat);
        delete[] fat;
    }

    char get_fat_item(int idx) {
        char *fat, *tmp;
        fat = new char [get_block_count()*2];
        read_fat(fat);
        char c = *(fat+idx);
        delete[] fat;
        return c;
    }

    bool is_valid_name (string &str) {//判断文件名是否符合规矩
        if(str.find("\\", 0) != -1) {
            alert("The file or directory name includes illegal characters");
            return false;
        }else if(str.length() > 8) {
            alert("The file or directory name can not exceed 8 characters");
            return false;
        }else if(str == "." || str == "..") {
            alert("The file or directory name can not make '.' Or '..'");
            return false;
        }
        return true;
    }

    void display_vd_content(int pos, int length) {//显示内容核心
        ifstream in(format_file_name.c_str(), ios::binary|ios::in);
        if(!in.is_open()) {
            alert("Failed to open file!!");
            return;
        }
        in.seekg(pos, ios::beg);
        int  i = 0;
        char c;
        while(i < length) {
            printf("%08d  ", pos+i);
            for(int j = 0; j < 16; j++) {
                char tmp[20];
                in.read(&c, 1);
                if(in.eof()) {
                    break;
                }
                sprintf(tmp, "%02x", c);
                if(strlen(tmp) > 2) {
                    string tmm = tmp;
                    cout<<tmm.substr(strlen(tmp)-2, 2)<<" ";
                }else {
                    printf("%02x ",c);
                }
                            i++;
            }
            in.seekg(-16, ios::cur);
            cout<<"  ";
            for(int j = 0; j < 16; j++) {
                in.read(&c, 1);
                if(in.eof()) {
                    break;
                }
                if(c > 13  &&  c < 127) {
                    cout<<c;
                }else {
                    cout<<".";
                }
            }

            cout<<endl;
        }
        in.close();
    }

    void display_content(string &str1, string &str2) {//显示内容
        int start = to_integer(str1);
        if(start >= 0) {
            int length = to_integer(str2);
            if(length > 0) {
                display_vd_content(start, length);
            }else {
                display_vd_content(start, 256);
            }
        }else {

        }
    }

    void display_content(string &str1) {

        toLowerCase(str1);

        if(str1 == "fat") {
            ifstream in (format_file_name.c_str(), ios::in|ios::binary|ios::ate);
            long size = in.tellg();
            in.close();
            display_vd_content(0, (size/(BLOCK_SIZE+2))*2 );
        }
    }

    void write_directory_content(int block_no, int parent_block_no, char *dateTime) {
        char *directory_content = new char[BLOCK_SIZE];
        memset(directory_content, 0, BLOCK_SIZE);
        FCB *tmp = (FCB *)directory_content;
        strcpy(tmp->name , ".");
        strcpy(tmp->dateTime, dateTime);
        tmp->size = BLOCK_SIZE;
        tmp->first_block = block_no;
        tmp->type = 2;
        tmp++;
        strcpy(tmp->name , "..");
        strcpy(tmp->dateTime, dateTime);
        tmp->size = BLOCK_SIZE;
        tmp->first_block = parent_block_no;
        tmp->type = 2;
        tmp++;
        write_block(block_no, directory_content);
        delete []directory_content;
    }

    void do_format(string &str, int integer, int Bsize) {//创建FAT表文件
        if(!is_power_of_two(integer)) {
            alert("Not the power of 2");
        } else if (integer > 65535) {//64K minus FAT minus 0000
            alert("Exceeds the maximum memory range");
        } else {
            ofstream out(str.c_str(), ios::out|ios::binary);
            if(!out.is_open()) {
                alert("Failed to create file!!");
            } else {
                format_file_name = str;
                cout<<"Formatting:  "<<str<<", BlockSize:  "<<Bsize<<", BlockNum:  "<<integer<<endl;

                int myByte = LAST_BLOCK;
                out.write((char*)&myByte, 2);
                myByte = EMPTY_BLOCK;
                for(int i = 0; i < integer-1; i++) {
                    out.write((char*)&myByte, 2);
                }
                char buf[BLOCK_SIZE];
                memset(buf, 0, BLOCK_SIZE);
                for(int i = 0; i < integer; i++) {
                    out.write(buf, BLOCK_SIZE);
                }
                char dateTime[15];
                setDateTime(dateTime);
                write_directory_content(0,0,dateTime);
                out.close();
            }
        }
    }




    void format(){
        string aa = "a";
        do_format(aa, 32, BLOCK_SIZE);
    }

    void help() {

    }


    FCB* get_directory_item(FCB *content, int type, char *name) {
        FCB *tmp = content;
        for(int i = 0; i < BLOCK_SIZE/sizeof(FCB); i++, tmp++) {
            if(tmp->type == type) {
                if(strcmp(tmp->name, name)==0) {
                    return tmp;
                }
            }
        }
        return NULL;
    }


    void md(char *name) {//创建目录
        string ss = name;
        if(!is_valid_name(ss)) {
            return;
        }
        FCB *directory_content = new FCB[BLOCK_SIZE];
        read_block(current_directory_block_no, (char *)directory_content);
        if(get_directory_item(directory_content, 1, name) != NULL  ||  get_directory_item(directory_content, 2, name) != NULL) {
            alert("Directory name is occupied");
            delete[] directory_content;
            return;
        }

        int block_no = get_empty_block_num(0);
        if(block_no < 0) {
            alert("insufficient space in drive");
            delete[] directory_content;
            return;
        }
        FCB *tmp = directory_content;
        for(int i = 0; i < BLOCK_SIZE/sizeof(FCB); i++, tmp++) {
            if(tmp->type == 0) {
                char dateTime[15];
                setDateTime(dateTime);
                strcpy(tmp->name, name);
                tmp->size = BLOCK_SIZE;
                tmp->first_block = block_no;
                strcpy(tmp->dateTime, dateTime);
                tmp->type=(char)2;
                write_block(current_directory_block_no, (char *)directory_content);
                set_fat_item(block_no, LAST_BLOCK);
                delete[] directory_content;
                write_directory_content(block_no, current_directory_block_no, dateTime);
                return;
            }
        }

    }

    void rd(string &name) {//删除目录
        char aa[100];
        strcpy(aa, name.c_str());
        if(!is_valid_name(name)) {
            return;
        }
        FCB *directory_content = new FCB[BLOCK_SIZE];
        read_block(0, (char *)directory_content);
        FCB *tmp, *tmp2;
        tmp = directory_content;
        tmp2 = get_directory_item(directory_content, 2, aa);
        if(tmp2 != NULL) {
            char *content = new char [BLOCK_SIZE];
            memset(content, 0, BLOCK_SIZE);
            int block_no = tmp2->first_block;
            cout<<block_no<<endl;

            write_block(block_no, content);
            set_fat_item(block_no, EMPTY_BLOCK);
            memset((char *)tmp2, 0, sizeof(FCB));
                write_block(0, (char *)directory_content);
                delete[] directory_content;


        }else {
            cout<<"Not Find Name"<<endl;
        }
    }

    void dir() {//显示目录
        FCB *directory_content = new FCB [BLOCK_SIZE];
        read_block(current_directory_block_no, (char *)directory_content);
        FCB *tmp = directory_content;
        for(int i = 0; i < BLOCK_SIZE/sizeof(FCB); i++, tmp++) {
            if(tmp->type == 1 || tmp->type == 2) {
                int type = tmp->type;
                if(tmp->first_block >=0 ) {
                    printf("%d\t", tmp->first_block);
                }else {
                    printf("\t");
                }

                *(tmp->dateTime+15) = 0;
                printf("%s\t", tmp->dateTime);
                if(type == 2) {
                    printf("<DIR>\t");
                }else {
                    printf("%d\t", tmp->size);
                }
                printf("%s\n", tmp->name);
            }
        }
        delete []directory_content;
    }

    void cd(string &name) {//定位

        if(name == "NULL") {
            if(current_directory.length() == 0) {
                cout<<"\\ "<<endl;
            }else {
                cout<<current_directory<<endl;
            }
        }else if(name == ".") {
            return;
        }else if(name == "\\"){
            current_directory_block_no = 0;
            current_directory = "";
            return;
        }else {
            FCB *directory_content = new FCB [BLOCK_SIZE];
            read_block(current_directory_block_no, (char *)directory_content);
            char name1[100];
            strcpy(name1, name.c_str());
            FCB *tmp = get_directory_item(directory_content, 2, name1);
            if(tmp == NULL) {
                alert("Not Find Contents");
            }else {
                current_directory_block_no = tmp->first_block;
                current_directory+="\\";
                current_directory+=name1;
            }
            delete []directory_content;
        }

    }

    void mk(char *name, int size, char *content) {//创建文件
        string ss = name;
        if(!is_valid_name(ss)) {
            return;
        }
        FCB *directory_content = new FCB[BLOCK_SIZE];
        read_block(current_directory_block_no, (char *)directory_content);
        if(get_directory_item(directory_content, 1, name) != NULL  ||  get_directory_item(directory_content, 2, name) != NULL) {
            alert("Directory name is occupied");
            delete[] directory_content;
            return;
        }

        int block_no = get_empty_block_num(0);
        if(block_no < 0) {
            alert("insufficient space in drive");
            delete[] directory_content;
            return;
        }


        FCB *tmp = directory_content;
        for(int i = 0; i < BLOCK_SIZE/sizeof(FCB); i++, tmp++) {
            if(tmp->type == 0) {
                char dateTime[15];
                setDateTime(dateTime);
                strcpy(tmp->name, name);
                strcpy(tmp->dateTime, dateTime);
                tmp->type=(char)1;
                tmp->size = size;
                if(size > 0) {
                    tmp->first_block = block_no;
                    int block_count = (int)ceil(size/(double)BLOCK_SIZE);
                    int *block_numbers = new int[sizeof(int)*block_count];
                    *block_numbers = block_no;
                    for(int j = 1; j < block_count; j++) {
                        *(block_numbers+j) = get_empty_block_num(*(block_numbers + j - 1) + 1);
                        if(*(block_numbers + j) == -1) {
                            alert("There is not enough memory space");
                            delete[] block_numbers;
                            delete[] directory_content;
                            return;
                        }
                    }
                    for(int j = 0; j < block_count; j++) {
                        if( (j+1) == block_count) {
                            set_fat_item(*(block_numbers + j), LAST_BLOCK);
                        }else {
                            set_fat_item(*(block_numbers + j), *(block_numbers + j + 1));
                        }
                        write_block(*(block_numbers+j), (char *)(content+BLOCK_SIZE*j));

                    }
                    delete[] block_numbers;


                }else {
                    tmp->first_block = -1;
                }
                write_block(current_directory_block_no, (char *)directory_content);
                delete[] directory_content;

                return;
            }
        }
        alert("The parent directory is full");
        delete[] directory_content;
    }

    void del(string &name) {//删除文件

    }

    void put(string &src, string &dest) {
        FILE *fp = fopen(src.c_str(), "rb");
        if(fp == NULL) {
            alert("Did not find the local file");
        }else {
            int size = get_file_size(src);
            char *content = new char [(int)(ceil(size/(double)BLOCK_SIZE)) * BLOCK_SIZE];
            memset(content, 0, ceil(size/(double)BLOCK_SIZE) * BLOCK_SIZE);
            fread(content, size, 1, fp);
            if(dest == "NULL") {
                char aa[100];
                strcpy(aa, src.c_str());
                mk(aa, size, content);
            }else {
                char bb[100];
                strcpy(bb, dest.c_str());
                mk(bb, size, content);
            }
            delete[] content;
        }
        fclose(fp);
    }

}



#endif // DOS_H_INCLUDED

主函数文件

#include <iostream>
#include <string>
#include <cstdlib>
#include <ctime>
#include "windows.h"
#include "FCB.h"
#include "DOS.h"



//char current_directory[256] = "";//当前目录

//char format_file_name[32];//虚拟磁盘文件名



using namespace std;
using namespace DOS;

int main()
{
        /*char *content = new char [sizeof(FCB)];
            memset(content, 0, sizeof(FCB));
            cout<<content<<endl;
        return 0;*/
    while(1) {
        string cmd, str[10];
        int length;
        if(current_directory.length() == 0) {
            cout<<"\\$ ";
        }else {
            cout<<current_directory<<"$ ";
        }
        getline(cin,cmd);
        length = split(cmd, str, ' ');
        toLowerCase(str[0]);


        if(str[0] == "exit") {
            exit(0);
        } else if(str[0] == "cls") {
            system("cls");
        } else if(str[0] == "help" || str[0] == "?") {
            help();
        } else if(str[0] == "format") {
            if(length == 3) {
                do_format(str[1], to_integer(str[2]), BLOCK_SIZE);
            }else {
                format();
            }
        } else if(str[0] == "info") {
            if(length == 2) {
                display_content(str[1]);
            }else if (length == 3) {
                display_content(str[1], str[2]);
            }else {
                alert("Error command!");
            }
        } else if(str[0] == "md" && length == 2) {
            char aa[100];
            strcpy(aa, str[1].c_str());
            md(aa);
        } else if(str[0] == "dir") {
            dir();
        } else if(str[0] == "cd"){
            //char bb[100];
            //strcpy(bb, str[1].c_str());
            if(length == 2) {
                cd(str[1]);
            }else {
                string bb = "NULL";
                cd(bb);
            }
        } else if(str[0] == "mk" && length == 2){
            char bb[100];
            strcpy(bb, str[1].c_str());
            mk(bb, 0, NULL);
        } else if(str[0] == "mk" && length == 3){
            int size = to_integer(str[2]);
            if(size > 0) {
                char *content = (char *)malloc(size);
                memset(content, 0, size);
                char cc[100];
                strcpy(cc, str[1].c_str());
                mk(cc, size, content);
            }
        } else if(str[0] == "put" && length == 2){
            string cc = "NULL";
            put(str[1], cc);
        } else if(str[0] == "put" && length == 3){
            put(str[1], str[2]);
        } else if(str[0] == "rd" && length == 2){
            rd(str[1]);
        } else if(str[0] == "del" && length == 2){

        } else {
            alert("Error command!");
        }
    }


    return 0;
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值