【文件管理】操作系统简易文件管理系统

前言:

在一篇博客基础上,做了大幅度改动,时间仓促,代码冗余较多,耦合度高。仅供参考。

参考blog: 磁盘文件管理

指令集:

ls & ll 列出文件/目录
touch [文件名]: 创建文件
echo [内容] > [文件名] 覆盖
echo [内容] >> [文件名] 追加
cd [相对路径/绝对路径] : 进入某个目录
cd .. : 返回上一级
mkdir [相对路径/绝对路径] : 创建目录
mkdir -p [相对路径/绝对路径] : 创建多级目录
rm [路径] : 删除文件
rm -r [路径] : 删除目录文件或者文件
exit: 退出

运行截图:

【文件管理】操作系统简易文件管理系统_第1张图片

【文件管理】操作系统简易文件管理系统_第2张图片

【文件管理】操作系统简易文件管理系统_第3张图片

代码:

1.文件/目录的实体类:

import java.io.Serializable;
import java.util.HashMap;

import java.util.Map;

public class FileModel implements Serializable {
    public Map subMap = new HashMap();
    private String name; //文件名或目录名
    private int attr; //用来识别是文件还是目录
    private int startNum;    //在FAT表中起始位置
    private int size;    //文件的大小
    private String content;//只有文件才能有这个字段
    private FileModel father = null;    //该文件或目录的上级目录


    public FileModel(String name){
        this.name = name;
    }
    public FileModel(String name, int startNum, int size) {
        this.name = name;
        this.attr = 2;
        this.startNum = startNum;
        this.size = size;
    }

    public FileModel(String name, int startNum) {
        this.name = name;
        this.attr = 3;
        this.startNum = startNum;
        this.size = 0;
    }
    //getter,setter方法...
}

2.文件管理:

import com.system.utils.OSUtils;
import com.system.utils.Utils;
import com.system.entity.FileModel;

import java.util.*;

public class OSManager {

    private static int TOTAL_BLOCKS = 128;
    //定义FAT表
    private static int[] fat = new int[TOTAL_BLOCKS];
    //创建根目录(名字,在fat表中的起始位置)
    private FileModel root = new FileModel("\\", 1);
    //当前打开的目录
    private FileModel nowCatalog = root;
    //磁盘块能够存放的字节数
    private static int BLOCK_BIT = 10;//假设一个磁盘块容纳的字节数量

    //初始化
    public OSManager() {
        //初始化fat表
        //将第一位设置为跟文件的空间
        Arrays.fill(fat, 0);
        fat[1] = -1;//代表这块磁盘已经被占用
        fat[0] = 126;//第0块代表有多少是空闲的
        root.setFather(null);
    }

    /**
     * 创建文件
     *
     * @param name 文件名
     * @param size 大小
     */
    public void createFile(String name, int size) {
        //判断磁盘空间是否足够
        if (fat[0] >= size) {
            //在当前目录下查找是否有同名目录或者文件
            FileModel fileModel = nowCatalog.subMap.get(name);
            if (fileModel == null) {//文件存在
                //如果当前目录下面没有这个文件  那么继续创建即可
                //分配磁盘块
                int startNum = setFat(size);
                FileModel newFile = new FileModel(name, startNum, size);
                //记录他的父级
                newFile.setFather(nowCatalog);
                //父级增加
                FileModel father = newFile.getFather();
                while (father != root) {
                    father.setSize(father.getSize() + size);
                    father = father.getFather();
                }
                //在目录下添加该文件
                nowCatalog.subMap.put(name, newFile);
                fat[0] -= size;
                System.out.println("文件创建成功");
            } else {
                System.out.println("创建失败,文件已经存在!");
            }
        } else {
            System.out.println("创建文件失败,磁盘空间不足!");
        }
    }

    /**
     * 创建层级目录
     *
     * @param start 如果是绝对路径创建,那么start为root;如果相对路径创建,那么start为当前目录
     * @param name  假设创建/usr/local 那么name为{“usr”,"local"}
     */
    public void createFileOrCatalog(FileModel start, String[] name) {
        int len = name.length;
        if (fat[0] >= len) {
            FileModel cur = start;
            for (int i = 0; i < name.length; i++) {
                if (!cur.subMap.containsKey(name[i])) {//如果存在 那么不需要再创建
                    FileModel fileModel = new FileModel(name[i]);
                    fileModel.setAttr(3);
                    cur.subMap.put(name[i], fileModel);
                    fileModel.setFather(cur);
                }
                cur = cur.subMap.get(name[i]);
            }
        } else {
            System.out.println("创建目录失败,磁盘空间不足!");
        }
    }

    public void showBreadLine() {
        //面包线
        FileModel cur = nowCatalog;
        Deque deque = new LinkedList<>();
        deque.push(">");
        if (cur != root) {
            while (cur != root) {
                deque.push(cur.getName());
                deque.push("\\");
                cur = cur.getFather();
            }
        } else {
            deque.push("\\");
        }
        deque.push("C:");
        StringBuilder sb = new StringBuilder();
        while (!deque.isEmpty()) {
            sb.append(deque.pop());
        }
        System.out.print(sb.toString());
    }

    //显示目下所有的文件信息
    //C:\root>
    public void showFiles() {
        System.out.println("-----------------------------------------------------------------------------");
        //文件状态
        if (!nowCatalog.subMap.isEmpty()) {
            System.out.printf("%-8s  %-8s  %-8s %-8s %-12s\n", "文件名", "操作类型", "起始盘块", "大小(块)", "磁盘号(块)");
            for (FileModel model : nowCatalog.subMap.values()) {
                if (model.getAttr() == 2) {
                    String blocks = getBlocks(model.getStartNum()).toString();
                    System.out.printf("%-8s  %-9s  %-12d %-8d %-12s\n", model.getName(),
                            "可读可写文件",
                            model.getStartNum(),
                            model.getSize(),
                            blocks.substring(1, blocks.length() - 1));
                } else if (model.getAttr() == 3) {
                    System.out.printf("%-8s  %-9s\t %-12s %-8d %-12s\n", model.getName(),
                            "目录",
                            "---",
                            model.getSize(),
                            "---");
                }
            }
        } else {
            System.out.println("当前目录下没有文件!");
        }
        //磁盘空闲信息
        System.out.println("-----------------------------------------------------------------------------");
        System.out.printf("%-10s\t%-10s\t%-10s\n", "磁盘总容量(块)", "占用率", "剩余容量(块)");
        System.out.printf("%-10s\t\t%-10s\t\t%-10s\n", TOTAL_BLOCKS, Utils.d2s((TOTAL_BLOCKS - fat[0]) * 1.0 / TOTAL_BLOCKS), fat[0]);
        System.out.println("-----------------------------------------------------------------------------");
    }


    public List getBlocks(int startNum) {
        List ans = new ArrayList<>();
        int cur = startNum;
        while (fat[cur] != -1) {
            ans.add(cur);
            cur = fat[cur];
        }
        ans.add(cur);
        return ans;
    }

    private int isDir(FileModel start, String[] names) {
        FileModel cur = start;
        for (int i = 0; i < names.length; i++) {
            if (cur.getAttr() == 3 && cur.subMap.containsKey(names[i])) {
                cur = cur.subMap.get(names[i]);
            } else {
                return -2;//表示文件不存在
            }
        }
        if (cur.getAttr() == 3) {//文件夹
            return 1;
        }
        return -1;//文件
    }

    /*
      递归删除某个目录以及下面的内容
     */
    public void deleteCatalog(FileModel start, String[] path) {
        FileModel cur = start;
        for (int i = 0; i < path.length; i++) {
            if (cur.subMap.containsKey(path[i])) {
                cur = cur.subMap.get(path[i]);
            } else {
                System.out.println("删除失败,目录不存在!");
                return;
            }
        }
        cur.getFather().subMap.remove(cur.getName());//将其从父级目录中删除

        if (cur.getAttr() == 3) {//文件夹
            delDfs(cur);
        } else {
            delFat(cur.getStartNum());//文件
            fat[0] += cur.getSize();
            FileModel father = cur.getFather();
            while (father != null) {
                father.setSize(father.getSize() - cur.getSize());
                father = father.getFather();
            }
        }
        cur.subMap = null;
    }


    private void delDfs(FileModel fileModel) {
        Iterator> iterator = fileModel.subMap.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry entry = iterator.next();
            if (entry.getValue().getAttr() == 3) {
                delDfs(entry.getValue());
            } else {//如果是文件
                fat[0] += entry.getValue().getSize();
                delFat(entry.getValue().getStartNum());//回收文件空间
                FileModel father = entry.getValue().getFather();
                while (father != root) {
                    father.setSize(father.getSize() - entry.getValue().getSize());
                    father = father.getFather();
                }
            }
        }
    }

    /*
    对文件进行重命名
     */
    public void reName(String name, String newName) {
        if (nowCatalog.subMap.containsKey(name)) {
            if (!nowCatalog.subMap.containsKey(newName)) {
                //获取原文件
                FileModel fileModel = nowCatalog.subMap.get(name);
                fileModel.setName(newName);
                nowCatalog.subMap.remove(name);
                nowCatalog.subMap.put(newName, fileModel);
                System.out.println("重命名成功");
            } else {
                System.out.println("重命名失败,同名文件已经存在");
            }
        } else {
            System.out.println("重命名失败,没有该文件");
        }
    }

    //假设我要创建  mkdir -p /find/usr/local[usr不存在的情况] mkdir /find/usr/local [usr存在]
    //使用-p还是不使用取决于我创建的是否是多级目录
    private boolean canCreate(FileModel start, String[] path, int len) {
        FileModel cur = start;
        for (int i = 0; i < len; i++) {
            if (!cur.subMap.containsKey(path[i])) {
                return false;
            } else if (cur.subMap.get(path[i]).getAttr() == 2) {//如果包含 但是是文件类型 这种情况直接创建失败
                return false;
            }
            cur = cur.subMap.get(path[i]);
        }
        return true;
    }

    /*
    返回上级目录
     */
    public void backFile() {
        if (nowCatalog.getFather() == null) {
            System.out.println("已经是顶级目录");
        } else {
            nowCatalog = nowCatalog.getFather();
        }
    }

    /*
    通过绝对路径的方式找到文件 /user/local/bin  将其分解为
     */
    public void openCatalog(FileModel start, String[] loadName) {
        //从根向下查找
        FileModel cur = start;
        for (int i = 0; i < loadName.length; i++) {
            if (cur.subMap.containsKey(loadName[i])) {
                FileModel fileModel = cur.subMap.get(loadName[i]);
                if (fileModel.getAttr() == 3) {
                    cur = fileModel;
                } else {
                    System.out.println("目录不存在");
                    return;
                }
            } else {
                System.out.println("目录不存在");
                return;
            }
        }
        nowCatalog = cur;
    }

    //cat 文件名
    public void showContent(String name) {
        if (nowCatalog.subMap.containsKey(name)) {
            FileModel fileModel = nowCatalog.subMap.get(name);
            if (fileModel.getAttr() == 2) {
                System.out.println(fileModel.getContent());
            } else {
                System.out.println(name + "是一个目录!");
            }
        } else {
            System.out.println("文件不存在");
        }
    }

    /**
     * echo指令
     * 对内容进行编辑  type = 0,使用追加的方式 type = 1使用修改的方式
     *
     * @param name
     * @param type
     */
    public void updateContent(String name, int type, String content) {
        if (nowCatalog.subMap.containsKey(name)) {
            FileModel fileModel = nowCatalog.subMap.get(name);
            if (fileModel.getAttr() == 2) {
                if (type == 0) {
                    //当前能够容纳的字节数量
                    int hasBits = fileModel.getSize() * BLOCK_BIT;
                    //需要容纳的字节数量
                    int needBits = (fileModel.getContent() + content).getBytes().length;
                    if (needBits > hasBits) {
                        //开启磁盘
                        int addSize = (int) Math.ceil((needBits - hasBits) * 1.0 / BLOCK_BIT);
                        if (reAddFat(fileModel.getStartNum(), addSize) >= 0) {//如果追加成功
                            fat[0] -= addSize;
                            FileModel father = fileModel.getFather();
                            while (father != root) {
                                father.setSize(father.getSize() + addSize);
                                father = father.getFather();
                            }
                            fileModel.setSize(fileModel.getSize() + addSize);
                            fileModel.setContent(fileModel.getContent() + content);
                        } else {
                            System.out.println("磁盘空间不足,写文件失败!");
                        }
                    } else {
                        fileModel.setContent(fileModel.getContent() + content);
                    }
                } else if (type == 1) {
                    int hasBits = fileModel.getSize() * BLOCK_BIT;
                    int needBits = content.getBytes().length;
                    if (needBits > hasBits) {
                        int addSize = (int) Math.ceil((needBits - hasBits) * 1.0 / BLOCK_BIT);
                        if (reAddFat(fileModel.getStartNum(), addSize) >= 0) {
                            fat[0] -= addSize;
                            FileModel father = fileModel.getFather();
                            while (father != root) {
                                father.setSize(father.getSize() + addSize);
                                father = father.getFather();
                            }
                            fileModel.setSize(fileModel.getSize() + addSize);
                            fileModel.setContent(content);
                        } else {
                            System.out.println("磁盘空间不足,写文件失败!");
                        }
                    } else {
                        fileModel.setContent(content);
                    }
                }
            } else {
                System.out.println(name + "是一个目录!");
            }
        } else {
            System.out.println("文件不存在!");
        }
    }


    //关于fat的一些操作
    //分配 返回的是起始块号
    public static int setFat(int size) {
        int pre = -1;
        int startNum = pre;
        int count = 0;
        for (int i = 2; i < fat.length; i++) {
            if (fat[i] == 0) {//如果当前是空闲块
                if (pre != -1) {
                    fat[pre] = i;
                    pre = i;
                } else {
                    startNum = i;
                    pre = i;
                }
                count++;
                if (count == size) {
                    fat[i] = -1;//设置为文件的最后一块
                    break;
                }
            }
        }
        return startNum;
    }

    /*
    删除某个文件
     */
    public static void delFat(int startNum) {
        int cur = startNum;
        while (fat[cur] != -1) {
            //将这个位置设置为0
            int tmp = cur;
            cur = fat[cur];
            fat[tmp] = 0;
        }
        //将最后的设置为0
        fat[cur] = 0;
    }


    /*
    追加多少块
     */
    public static int reAddFat(int startNum, int addSize) {
        if (fat[0] >= addSize) {
            int curNum = startNum;
            while (fat[curNum] != -1) {
                curNum = fat[curNum];
            }
            int freeNum = setFat(addSize);
            fat[curNum] = freeNum;
            return 1;
        }
        return -1;
    }
    public void run() {
        //加载数据
        root = OSUtils.read();
        fat = OSUtils.read2();
        nowCatalog = root;
        Scanner scanner = new Scanner(System.in);
        boolean loop = true;
        while (loop) {
            showBreadLine();
            //对指令进行处理
            String[] split = scanner.nextLine().split(" ");

            String commend = split[0];

            if (commend.equals("cd")) {//这里需要区分使用的绝对路径还是相对路径
                String dirName = split[1];
                if ("..".equals(dirName)) {
                    backFile();
                } else if (dirName.startsWith("/")) { //绝对路径 例如/usr/local/bin 想要查找的是绝对路径
                    if ("/".equals(dirName)) {
                        openCatalog(this.root, new String[0]);
                    } else {
                        String[] filePath = dirName.substring(1).split("/");
                        openCatalog(this.root, filePath);
                    }
                } else {
                    //如果起始不是/ 相当于查找的是相对路径
                    String[] filePath = dirName.split("/");
                    openCatalog(this.nowCatalog, filePath);
                }
            } else if (commend.equals("mkdir")) {
                String dirName = "";
                if (split.length == 2) {
                    dirName = split[1];
                    if (dirName.startsWith("/")) {
                        String[] path = dirName.substring(1).split("/");
                        boolean canCreate = canCreate(this.root, path, path.length - 1);
                        if (canCreate) {
                            createFileOrCatalog(this.root, path);
                        } else {
                            System.out.println("创建失败!");
                        }
                    } else {
                        String[] path = dirName.split("/");
                        boolean canCreate = canCreate(this.nowCatalog, path, path.length - 1);
                        if (canCreate) {
                            createFileOrCatalog(this.nowCatalog, path);
                        } else {
                            System.out.println("创建失败!");
                        }
                    }
                } else if (split.length == 3) {
                    dirName = split[2];
                    if (dirName.startsWith("/")) {
                        createFileOrCatalog(this.root, dirName.substring(1).split("/"));
                    } else {
                        createFileOrCatalog(this.nowCatalog, dirName.split("/"));
                    }
                }
            } else if (commend.equals("touch")) {
                String fileName = split[1];
                createFile(fileName, 1);
            } else if (commend.equals("cat")) {
                String fileName = split[1];
                showContent(fileName);
            } else if (commend.equals("ls") || commend.equals("ll")) {
                showFiles();
            } else if (commend.equals("mv")) {
                String oldName = split[1];
                String newName = split[2];
                reName(oldName, newName);
            } else if (commend.equals("echo")) {
                String content = split[1];
                String type = split[2];
                String fileName = split[3];
                if (">>".equals(type)) {//追加
                    updateContent(fileName, 0, content);
                } else {//覆盖
                    updateContent(fileName, 1, content);
                }
            } else if (commend.equals("rm")) {
                if (split.length == 2) {//rm XXX  删除文件
                    //是相对路径 还是绝对路径
                    String name = split[1];
                    if (name.startsWith("/")) {//绝对路径 /usr/local/aa.txt
                        int isDir = isDir(this.root, name.substring(1).split("/"));
                        if (isDir == -2) {
                            System.out.println("文件不存在!");
                        } else if (isDir == 1) {
                            System.out.println("文件夹不能删除!");
                        } else {
                            deleteCatalog(this.root, name.substring(1).split("/"));
                        }
                    } else {
                        int isDir = isDir(this.nowCatalog, name.split("/"));
                        if (isDir == -2) {
                            System.out.println("文件不存在!");
                        } else if (isDir == 1) {
                            System.out.println("文件夹不能删除!");
                        } else {
                            deleteCatalog(this.nowCatalog, name.split("/"));
                        }
                    }
                } else if (split.length == 3) {
                    String name = split[2];
                    if (name.startsWith("/")) {
                        deleteCatalog(this.root, name.substring(1).split("/"));
                    } else {
                        deleteCatalog(this.nowCatalog, name.split("/"));
                    }
                }
            } else if (commend.equals("exit")) {
                loop = false;
                //持久化
                OSUtils.write(root);
                OSUtils.write2(fat);
            } else {
                System.out.println("指令不存在");
            }
        }
    }
}

3.读写文件工具类(在项目启动的时候,将dat文件中的数据加载到程序中,项目终止时持久化到dat文件中)

import java.io.*;

public class OSUtils {

    public static void write(FileModel root) {
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("file-system/src/model.dat"))) {
            oos.writeObject(root);
            oos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //从磁盘读取出来
    public static FileModel read() {
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("file-system/src/model.dat"))) {
            FileModel fileModel = (FileModel) ois.readObject();
            return fileModel;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
        return null;
    }

    //将数组写入文件
    public static void write2(int[] array) {
        try (BufferedWriter writer = new BufferedWriter(new FileWriter("file-system/src/os.dat"))) {
            String line = "";
            for (int i = 0; i < array.length; i++) {
                line += array[i];
                line += " ";
            }
            writer.write(line);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static int[] read2() {
        int[] arr = new int[128];
        int index = 0;
        try (BufferedReader reader = new BufferedReader(new FileReader("file-system/src/os.dat"))) {
            String[] split = reader.readLine().split(" ");
            for (String s : split) {
                arr[index++] = Integer.parseInt(s);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return arr;
    }
}

4.启动类

import com.system.service.OSManager;

public class Main {
    public static void main(String[] args) {
        new OSManager().run();
    }
}

你可能感兴趣的:(java)