zoukankan      html  css  js  c++  java
  • Simple File System

    This is my operating system class design.

    1.一段代码及其bug.

        class Program
        {
            static void Main(string[] args)
            {
                string file = "weidiao";
                if (File.Exists(file)) File.Delete(file);
                File.Create(file);
                FileStream s = new FileStream(file, FileMode.Truncate);
                s.Write(Encoding.Default.GetBytes("weidiao"),0,"weidiao".Length);
            }
        }

    错误说:有另一进程正在占用文件"weidiao".
    一开始我以为create创建文件必然会调用系统进程,即便是Threading.Sleep(3000)依旧不行;
    原因:create返回值是Filestream!!!!!!!!!!!!!!
    2.C语言的文件操作简单而灵活,就像C语言的其它部分一样.w,r,文本和二进制,有没有+,总共w,r,w+,r+,wb,rb,wb+,rb+十二种.各有各的用处,无法互相替代.w是文本写,文本写即便是用fwrite也会出一些问题.用fwrite必须用二进制方式写.
    3.任何东西都是可以自己实现的,程序员最大的特质在于能够在原子操作的基础上堆叠出奇妙纷呈的结构.不要因为库函数里没有,就打退堂鼓.
    C++是最大最全的语言,功能灵活巧妙.Java和C#是最优美的语言.
    4.人对于表达方式并没有思路,人不知道自己应该用什么方式进行表达.而一旦发现了那种表达方式,表达就会变得清晰明了,简洁易懂.
    C语言中的结构体就是这样一种东西,强制类型转换能够让程序员对一块固定大小的空间做出不同的解释.就像一个身体,给它套上不同的马甲,人就可以用马甲来描述人体的部位了:马甲第一个扣上是....马甲上蓝色斑点地方是....
    5.即便是错误的设计,也会产生一定程度上有意义的逻辑.
    文件夹包含若干块,每一块上的内容是子项
    文件包含若干块,每一块上的内容是字节
    目录是特殊的文件
    过于追求完美就会降低效率,
    计算机语言也是不完美的
    编不下去只能怪自己low,不能仅仅埋怨最初的设计.
    聪明人总是贪心,总是在既成事实面前,追求效益最大化.
    6.我想描述一种状态:
    一件事要求在五天之内完成,第一天满怀抱负,想着要做的多么多么高级,接下来几天患得患失,唯恐实现的不够灵活,于是进度缓慢.最后一天草草的弄了一个成品交上去了.这样一来,之前所做的许多规划都没有实现,反倒不如先实现一个简单的,然后一点一点往上加东西.其实,目标必须要明确,必须要清楚的知道自己想要的东西长什么样子.一旦明确了目标之后,就要斩钉截铁地去干,闪电一般迅速完成.

    ===============================

    一,目标及任务

    给你一块磁盘,磁盘的大小已知,分成若干块,每块的大小固定.任务就是对这个空间进行组织,管理,便于用户使用,也就是便于用户进行一些文件操作,比如增(包括添加文件和添加文件夹),删(包括增加文件和文件夹),改(包括改变文件和改变文件夹的内容),查(给出文件名或者文件夹名,找到对应项的内容).

    一言以蔽之,给你一亩三分地,愿种瓜就种瓜,愿种豆就种豆.这就是你的自留地.你的任务就是将这块空间组织好,使之有序,便于上述操作.

    二,规划和整体设计

    先创建一个大文件作为磁盘,以后一切操作都在这块空地上进行,并且是以块为单位进行操作.也就是说,每次一读就是读一整块,一写就是写一整块.

    本程序是1024块*64B/块=64kB.

    创建的大文件(也就是磁盘)大小是64kB,包括1024块.每次通过fseek函数调整文件读写位置,读写64B的内容.

    初始化时,将这1024块进行分配:

    第0块叫引导块,存放管理员用户名和密码.(在实际的文件系统中,这一块存放的是操作系统启动位置,操作系统也作为文件存放在磁盘上).

    第1块叫超级块,存放空闲块,进行空闲块的分配和释放,这一块常驻内存.

    第2块叫根目录,一旦进入系统就进入了此目录.

    第3块~第1023块是空闲块,用成组链接法组织起来,并与超级块挂钩.

    因为有1024块,所以块号是10位.为了便于编程,本程序用16位表示一个块号(也就是一个short).

    每一个文件的内容可以放在好多块上,最多是30块.也就是文件长度最大是:30块*64B/块=1920B.

    古人云:文件夹是特殊的文件,它的内容就是它所包含的子项.这里的子项指的是:名称+块号.一个子项占16B,一块上可以放4个子项,一个文件夹最多占30块,所以一个文件夹下面最多有120个儿子,也就是120个子项.

    三,数据结构设计

    1.组长块

    blockCnt块数:本组内空闲块的个数.

    nextLeader下一组的组长块.

    member[30]组员最多30个.存储空闲块号.

    一共32个short,占64B.正好占一块.整个系统一共1024块,每组31块,一共包含32组.

    struct Leader{
        short blockCnt;
        short nextLeader;
        short member[30];
    };

    2.目录项

    文件和文件夹共用下面的数据结构.当表示文件时,itemCnt表示此文件所占的字节数;当表示文件夹时,表示此文件所包含的子项的个数,子项就是文件夹的儿子,即子文件和子文件夹.

    struct Dir
    {
        short blockCnt;//本目录所占的块数
        short itemCnt;//子项的个数
        short data[30];//30个块号
    };

    1.子项

    子项既可以是文件,也可以是文件夹.

    一个Item包含了这个子项的很多信息:名称,地址,是否是文件.

    设计时一个Item占16B,结果没用完,留下5B留待扩展,比如可以添加文件权限,修改时间的信息.这与实际中的操作系统是不一样的,实际操作系统中的Item只包含名称和块号两部分内容,其余部分放在i节点上,这样做的目的是使一块上尽量容纳多个子项,查找时调入的块数尽量少.然而,这样做的缺点就是如果要查看一个文件的基本信息,就必须把一块调入.当使用ls指令查看文件夹下的内容时,就得调入很多块.所以,每个子项应包括最常用的内容,把不常用的内容放到另一个地方.

    struct Item{
        char name[8];
        short block;
        bool isFile;
        char ext[5];//扩展
    };

    4.块

    一个块表示一个文件的数据部分,共占64个字节.

    struct Block{

       char a[64];

    };

     

    scanner.h

     1 #include<string>
     2 using namespace std;
     3 #pragma once
     4 struct Scanner
     5 { 
     6     int si;
     7     char s[1000];
     8     Scanner(char ss[]){
     9         int i;
    10         for (i = 0; ss[i]; i++)s[i] = ss[i];
    11         s[i] = 0;
    12         si = 0;
    13         while (s[si] == ' ')si++;
    14     }
    15     bool hasNext(){
    16         return s[si] != 0;
    17     }
    18     string next(){
    19         string ans = "";
    20         while (s[si] != ' '&&s[si])ans += s[si++];
    21         while (s[si] == ' ')si++;
    22         return ans;
    23     }
    24 };
    25  

    path.h

    #include"disk.h"
    #include<string>
    #include<string.h>
    using namespace std;
    #pragma once
    struct Path{
        Item a[100];
        int ai;
        Path(){
            ai = 1;
            a[0].block = 2;
            a[0].isFile = false; 
            strcpy(a[0].name, "root");
        }
        void push(Item it){
            a[ai++] = it;
        }
        Item pop(){ 
            if (ai == 1){
                Item it; 
                it.block = -1;
                return it;
            }
            return a[--ai];
        }
        Item peek(){
            return a[ai - 1];
        }
        string gets(){
            string s = "";
            extern string str(char*);
            for (int i = 0; i < ai; i++){
                s +=string(a[i].name)+"\";
            }
            return s;
        }
        void home(){
            ai = 1;
        } 
    };

    disk.h

    #pragma once
    //组长块
    struct Leader{
        short blockCnt;
        short nextLeader;
        short member[30];
    };
    struct Dir
    {
        short blockCnt;
        short itemCnt;
        short data[30];
    };
    struct Item{
        char name[8];
        short block;
        bool isFile;
        char ext[5];
    };
    
    struct Block{
        char a[64];
    };

    main.cpp

    #include<iostream>
    #include<math.h>
    #include<string>
    #include<string.h>
    #include"scanner.h"
    #include"disk.h"
    #include"path.h"
    using namespace std;
    
    const char disk[] = "disk.txt";
    const int BlockCount = 1024;
    const int BlockCapacity = 64;
    const int BlocksPerGroup = 31;
    const int ItemsPerBlock = 4;
    const int BytesPerItem = 4;
    Leader super;
    
    string replace(string src, string olds, string news){
        string ans = "";
        for (int i = 0; i < src.length();){
            int j;
            for (j = 0; j < olds.length() && i + j < src.length(); j++){
                if (src[j + i] != olds[j]){
                    break;
                }
            }
            if (j == olds.length()){
                ans += news;
                i += j;
            }
            else{
                ans += src[i];
                i++;
            }
        }
        return ans;
    }
    void readBlock(short x, void *block){
        FILE*file = fopen(disk, "rb");
        fseek(file, x*BlockCapacity, 0);
        fread(block, sizeof(Block), 1, file);
        fclose(file);
    }
    void writeBlock(short x, void* block){
        FILE *file = fopen(disk, "rb+");
        fseek(file, x*BlockCapacity, 0);
        fwrite(block, sizeof(Block), 1, file);
        fclose(file);
    }
    
    Item getItem(short folder, const char name[8]){
        Dir dir; readBlock(folder, &dir);
        Item it; it.block = -1;
        int k = 0;
        for (int i = 0; i < dir.blockCnt; i++){
            Item a[4];
            readBlock(dir.data[i], a);
            for (int j = 0; j < 4 && k++ < dir.itemCnt; j++){
                if (strcmp(name, a[j].name) == 0){
                    it = a[j];
                    return it;
                }
            }
        }
        return it;
    }
    
    
    bool exist(short x, const char name[8]){
        Item it = getItem(x, name);
        if (it.block == -1)return false;
        else return true;
    }
    void format(){
        //删除旧磁盘,创建新磁盘,设置新磁盘长度
        remove(disk);
        FILE*file = fopen(disk, "w");//write会覆盖,没有文件就创建文件
        fseek(file, BlockCapacity*BlockCount - 1, 0);
        char c = 'a';
        fwrite(&c, 1, 1, file);
        fclose(file);
    
        //第0块
        char userName[8] = "root";
        char password[8] = "haha";
        Block b0;
        strcpy(b0.a, userName);
        strcpy(b0.a + 8, password);
        b0.a[16] = 0;//0个用户
        writeBlock(0, &b0);
    
        //初始化所有组长块
        int leader = BlockCount - BlocksPerGroup;
        for (; leader >= 3; leader -= BlocksPerGroup){
            Leader l;
            l.blockCnt = BlocksPerGroup - 1;
            l.nextLeader = leader + BlocksPerGroup;
            for (int i = 0; i < l.blockCnt; i++){
                l.member[i] = i + 1 + leader;
            }
            writeBlock(leader, &l);
        }
        //初始化超级块
        leader += BlocksPerGroup;
        Leader super;
        super.blockCnt = leader - 3;
        super.nextLeader = leader;
        for (int i = 0; i < super.blockCnt; i++)
            super.member[i] = 3 + i;
        writeBlock(1, &super);
    
        //根目录
        Dir root;
        root.blockCnt = 0;
        root.itemCnt = 0;
        writeBlock(2, &root);
    }
    int allocBlock(){
        if (super.blockCnt == 0){
            int ans = super.nextLeader;
            if (ans == BlockCount)return -1;
            readBlock(ans, &super);
            return ans;
        }
        else{
            return super.member[--super.blockCnt];
        }
    }
    void freeBlock(short x){
        if (super.blockCnt == BlocksPerGroup - 1){
            writeBlock(x, &super);
            super.blockCnt = 0;
            super.nextLeader = x;
        }
        else{
            super.member[super.blockCnt++] = x;
        }
    }
    void readFile(short x, char s[]){
        Dir dir;
        readBlock(x, &dir);
        int k = 0;
        for (int i = 0; i < dir.blockCnt; i++){
            Block data;
            readBlock(dir.data[i], &data);
            for (int j = 0; j < BlockCapacity&&k < dir.itemCnt; j++)
                s[k++] = data.a[j];
        }
        s[k] = 0;
    }
    void writeFile(short x, char s[]){
        Dir dir;
        readBlock(x, &dir);
        int itemCnt = 1 + strlen(s);
        int blockCnt = ceil(1.0*itemCnt / BlockCapacity);
        if (blockCnt>dir.blockCnt){
            for (int i = dir.blockCnt; i < blockCnt; i++){
                dir.data[i] = allocBlock();
            }
        }
        else if (blockCnt < dir.blockCnt){
            for (int i = blockCnt; i < dir.blockCnt; i++){
                freeBlock(dir.data[i]);
            }
        }
        dir.itemCnt = itemCnt;
        dir.blockCnt = blockCnt;
        int k = 0;
        for (int i = 0; i < dir.blockCnt; i++){
            Block data;
            for (int j = 0; j < BlockCapacity&&k < dir.itemCnt; j++)
                data.a[j] = s[k++];
            writeBlock(dir.data[i], &data);
        }
        writeBlock(x, &dir);
    }
    int addItem(short x, const char *name, bool isFile){
        Dir dir;
        readBlock(x, &dir);
        if (exist(x, name)){
            cout << "此文件夹中已经包含同名文件或文件夹" << endl;
            return -1;
        }
        int pos = dir.itemCnt % 4;
        if (pos == 0){
            dir.blockCnt++;
            dir.data[dir.blockCnt - 1] = allocBlock();
        }
        Item t[4];
        readBlock(dir.data[dir.blockCnt - 1], t);
        strcpy(t[pos].name, name);
        t[pos].isFile = isFile;
        t[pos].block = allocBlock();
        writeBlock(dir.data[dir.blockCnt - 1], t);
    
        Dir it; it.blockCnt = 0; it.itemCnt = 0;
        writeBlock(t[pos].block, &it);
    
        dir.itemCnt++;
        writeBlock(x, &dir);
        return t[pos].block;
    }
    void deleteFile(short x){
        Dir dir;
        readBlock(x, &dir);
        for (int i = 0; i < dir.blockCnt; i++){
            freeBlock(dir.data[i]);
        }
        freeBlock(x);
    }
    void deleteFolder(short x){
        Dir dir;
        readBlock(x, &dir);
        int k = 0;
        for (int i = 0; i < dir.blockCnt; i++){
            Item a[4];
            readBlock(dir.data[i], a);
            for (int j = 0; j < 4 && k++ < dir.itemCnt; j++){
                if (a[j].isFile){
                    deleteFile(a[j].block);
                }
                else {
                    deleteFolder(a[j].block);
                }
            }
            freeBlock(dir.data[i]);
        }
        freeBlock(x);
    }
    void deleteItem(short folder, const char name[8]){
        Dir dir;
        readBlock(folder, &dir);
        int k = 0;
        for (int i = 0; i < dir.blockCnt; i++){
            Item a[4];
            readBlock(dir.data[i], a);
            for (int j = 0; j < 4 && k++ < dir.itemCnt; j++){
                if (strcmp(name, a[j].name) == 0){
                    if (a[j].isFile){
                        deleteFile(a[j].block);
                    }
                    else{
                        deleteFolder(a[j].block);
                    }
                    Item last[4];
                    readBlock(dir.data[dir.blockCnt - 1], last);
                    a[j] = last[(dir.itemCnt - 1) % 4];
                    writeBlock(dir.data[i], a);
                    if (dir.itemCnt % 4 == 1){
                        dir.blockCnt--;
                        freeBlock(dir.data[dir.blockCnt]);
                    }
                    dir.itemCnt--;
                    writeBlock(folder, &dir);
                    return;
                }
            }
        }
    }
    void start(){
        FILE*file = fopen(disk, "r");
        if (file == 0){
            cout << "磁盘不存在,将要进行新建磁盘并格式化" << endl;
            format();
        }
        readBlock(1, &super);
    }
    void exit(){
        writeBlock(1, &super);
    }
    void debugGroup(){
        writeBlock(1, &super);
        int k = 0;
        for (int leader = 1; leader < BlockCount&&k++ < 6;){
            Leader l;
            readBlock(leader, &l);
            cout << "leader " << leader << " " << l.blockCnt << ":";
            for (int i = 0; i < l.blockCnt; i++){
                cout << l.member[i] << " ";
            }
            cout << endl;
            leader = l.nextLeader;
        }
    }
    void ls(short x){
        Dir dir;
        readBlock(x, &dir);
        int k = 0;
        const int len = 28;
        char table[len];
        for (int i = 0; i < len; i++)table[i] = '-';
        table[len - 1] = 0;
        cout << table << endl;
        for (int i = 0; i < dir.blockCnt; i++){
            Item a[4];
            readBlock(dir.data[i], a);
            for (int j = 0; j < 4 && k++ < dir.itemCnt; j++){
                printf("| %-10s | %-10s |
    ", a[j].name, a[j].isFile ? "文件" : "文件夹");
            }
        }
        cout << table << endl;
    }
    int filelen(FILE*file){
        fseek(file, 0, 2);
        return ftell(file);
    }
    //a little difficult
    void tree(short x, const char*name, bool isFile,string prefix, string &treeString){
        treeString += prefix + name + "
    "; 
        if (isFile)return;
        string temp =replace(prefix,"", "");
        temp = replace(temp,"", "  ");
        temp = replace(temp,"", "  "); // 一定要注意,一个这个符号是两个空格
        Dir dir; readBlock(x, &dir);
        int k = 0;
        for (int i = 0; i < dir.blockCnt; i++){
            Item a[4]; readBlock(dir.data[i], a);
            for (int j = 0; j < 4 && k++ < dir.itemCnt; j++){
                if (k == dir.itemCnt)
                    tree(a[j].block,a[j].name,a[j].isFile,temp + "┗━", treeString);
                else 
                tree(a[j].block, a[j].name,a[j].isFile ,temp + "┣━", treeString);
            }
        } 
    }
    char cmds[100][100] = {
        "newfile  fileName", "创建新文件",
        "newfolder folderName ", "创建新文件夹",
        "cd 文件夹名 ", "进入子文件夹",
        "show 文件名", "显示子文件内容",
        "ls", "显示当前目录下的全部子项",
        "tree", "显示以当前目录为根的树形结构",
        "home ", "返回根目录",
        "back ", "返回上级目录",
        "del  文件名或者文件夹名 ", "删除当前目录下的文件或文件夹",
        "writefile 文件名  文本文件名", "写入文件",
        "format", "格式化磁盘",
        "exit", "退出系统",
        "help", "帮助",
        "debug", "显示磁盘使用情况",
        "#"
    };
    void help(){
        char table[64];
        for (int i = 0; i < 64; i++)table[i] = '-';
        table[63] = 0;
        for (int i = 0; strcmp(cmds[i], "#"); i += 2){
            if (i == 0)printf("		%s
    ", table);
            printf("		|%-30s|%-30s|
    ", cmds[i], cmds[i + 1]);
            printf("		%s
    ", table);
        }
    }
    void run(){
        char cmd[100];
        Path p;
        cout << "请您一定要注意,退出时要使用exit指令退出,不要关闭控制台" << endl;
        cout << "因为程序需要用exit()做一些善后工作" << endl;
        cout << "请使用help命令查看帮助" << endl;
        while (cout << p.gets() << ">" , gets(cmd)){
            Scanner s(cmd);
            string one = s.next();
            if (one == "")continue;
            else if (one == "format"){
                cout << "格式化将会清空全部文件及文件夹" << endl;
                cout << "您真的要清空吗?(Y/N)" << endl;
                gets(cmd); Scanner ss = Scanner(cmd);
                string c = ss.next();
                if (c == "y" || c == "Y")
                    format(), start(),p.home(), cout << "格式化成功" << endl;
                else cout << "取消格式化" << endl;
                start();
            }
            else if (one == "help"){
                cout << "您可以使用以下指令" << endl;
                help();
            }
            else if (one == "ls"){
                cout << p.gets() << endl;
                ls(p.peek().block);
            }
            else if (one == "home"){
                p.home();
            }
            else if (one == "back"){
                p.pop();
            }
            else if (one == "exit"){ 
                break;
            }
            else if (one == "tree"){
                Item it = p.peek();
                string tr = "";
                cout << "---------------------------" << endl;
                tree(it.block, it.name, 0, "", tr);
                cout << "---------------------------" << endl;
                cout << tr << endl;
            }
            else if (one == "del"){
                if (s.hasNext() == false){
                    cout << "命令格式错误,缺少文件名" << endl;
                    continue;
                }
                string file = s.next();
                const char *name = file.c_str();
                if (file.length() > 8 || !exist(p.peek().block, name)){
                    cout << "不存在这样的文件" << endl;
                    continue;
                }
                Item it = getItem(p.peek().block, name);
                deleteItem(p.peek().block, name);
            }
            else if (one == "newfile" || one == "newfolder"){
                if (s.hasNext() == false){
                    cout << "命令格式错误,缺少文件名" << endl;
                    continue;
                }
                string file = s.next();
                const char *name = file.c_str();
                if (file.length() > 8){
                    cout << "文件名太长" << endl;
                    continue;
                }
                if (exist(p.peek().block, name)){
                    cout << "已经存在名为" << file << "的文件了" << endl;
                    continue;
                }
                bool isFile = (one == "newfile");
                addItem(p.peek().block, name, isFile);
            }
            else if (one == "cd"){
                if (s.hasNext() == false){
                    cout << "命令格式错误" << endl;
                    continue;
                }
                string son = s.next();
                const char* name = son.c_str();
                if (son.length() > 8 || !exist(p.peek().block, name)){
                    cout << "不存在这样的文件" << endl;
                    continue;
                }
                Item it = getItem(p.peek().block, name);
                if (it.isFile){
                    cout << "不能进入文件,请输入文件夹" << endl;
                    continue;
                }
                p.push(it);
            }
            else if (one == "show"){
                if (s.hasNext() == false){
                    cout << "命令格式错误" << endl;
                    continue;
                }
                string son = s.next();
                const char* name = son.c_str();
                if (son.length() > 8 || exist(p.peek().block, name) == 0){
                    cout << "不存在这样的文件" << endl;
                    continue;
                }
                Item it = getItem(p.peek().block, name);
                if (it.isFile == 0){
                    cout << son << "不是文件,而是文件夹" << endl;
                    continue;
                }
                char content[BlockCapacity * 30];
                readFile(it.block, content);
                cout << content << endl;
            }
            else if (one == "del"){
                if (s.hasNext() == false){
                    cout << "命令格式错误" << endl;
                    continue;
                }
                string son = s.next();
                const char*name = son.c_str();
                if (son.length() > 8 || exist(p.peek().block, name) == 0){
                    cout << "不存在这样的文件" << endl;
                    continue;
                }
                Item it = getItem(p.peek().block, name);
                deleteItem(p.peek().block, it.name);
            }
            else if (one == "writefile"){
                if (s.hasNext() == false){
                    cout << "命令格式错误" << endl;
                    continue;
                }
                string son = s.next();
                const char*name = son.c_str();
                if (son.length() > 8 || exist(p.peek().block, name) == 0){
                    cout << "不存在这样的文件" << endl;
                    continue;
                }
                Item it = getItem(p.peek().block, name);
                if (it.isFile==0){
                    cout << "不能往文件夹中写内容" << endl;
                    continue;
                }
                if (s.hasNext() == false){
                    cout << "命令格式错误" << endl;
                    continue;
                }
                string fin = s.next();
                FILE*ff = fopen(fin.c_str(), "r");
                if (ff == 0){
                    cout << "不存在名为" << fin << "的子文件" << endl;
                    continue;
                }
                int len = filelen(ff);
                if (len > BlockCapacity * 30 - 1){
                    cout << fin << "文件太长" << endl;
                    continue;
                }
                char *content = new char[len + 1];
                fseek(ff, 0, 0);
                fread(content, len, 1, ff);
                content[len] = 0;
                writeFile(it.block, content);
                fclose(ff);
                delete content;
            }
            else if (one == "debug"){
                cout << "------------" << endl;
                debugGroup();
                cout << endl;
            }
            else {
                cout << "没有这样的命令,请输入help查看可用命令" << endl;
            }
            //这句话本来该省略,之所以加在这里是为了防止不用exit命令退出,那样会破坏系统.
            writeBlock(1, &super);
        }
    } 
    int main(){  
        start();
        run();
        exit();
        return 0;
    }
  • 相关阅读:
    SQL中的union
    SQL的类型转换
    Keytool生成证书
    Openssl生成证书
    Python示例-Json Parse
    Python示例-TCP Port Scan
    Python套接字
    TCP端口扫描
    Linux环境变量
    Python示例-Logging
  • 原文地址:https://www.cnblogs.com/weiyinfu/p/4936118.html
Copyright © 2011-2022 走看看