简易内存文件系统模拟

125 阅读4分钟

简易内存文件系统模拟

请模拟并实现一套简易的、基于内存的文件系统,该系统支持目录和文件的创建、删除、切换以及内容查询。

核心概念

  1. 树形结构: 文件系统是一个以根目录 / 为起点的树形结构。

  2. 路径 (Path):

    • 绝对路径:/ 开头,表示从根目录开始的完整路径,例如 /dir_a/dir_b
    • 相对路径: 不以 / 开头,表示相对于当前目录的路径,例如 dir_x/dir_y
  3. 名称唯一性: 在同一个目录下,所有文件和子目录的名称必须是唯一的。

  4. 初始状态: 系统初始化后,只有一个根目录 /,光标(当前工作目录)也位于根目录。

功能要求

你需要实现一个类,支持以下操作:

FileSystem()
  • 功能: 系统初始化。
  • 初始状态: 当前目录在根目录 /,且根目录下为空。
makeDir(string dirName)
  • 功能:当前目录下创建一个新的子目录。
  • 成功条件: dirName 与当前目录下的任何已有文件或目录的名称都不重复。
  • 返回值: 创建成功返回 true,否则返回 false
createFile(string fileName)
  • 功能:当前目录下创建一个新的文件。
  • 成功条件: fileName 与当前目录下的任何已有文件或目录的名称都不重复。
  • 返回值: 创建成功返回 true,否则返回 false
changeDir(string pathName)
  • 功能: 切换当前工作目录到 pathName 指定的位置。

  • 规则:

    • 如果 pathName"" (空字符串),当前目录保持不变,返回 true
    • 如果 pathName 指定的目录存在,则切换成功,返回 true
    • 如果 pathName 指定的目录不存在,则切换失败,当前目录保持不变,返回 false
  • 注意: pathName 可以是绝对路径或相对路径,且末尾可能带有一个 /

remove(string name)
  • 功能: 删除当前目录下名称为 name 的文件或目录。
  • 成功条件: 名称为 name 的文件或目录在当前目录下存在。
  • 注意 (递归删除): 如果删除的是一个目录,那么该目录下的所有子目录和文件也需要一并被递归删除。
  • 返回值: 删除成功返回 true,否则返回 false
listDir()
  • 功能: 返回当前目录下的所有目录和文件的名称列表。

  • 返回要求:

    • 不包含子目录下的内容。
    • 排序规则: 目录在前,文件在后;在各自的类别中,按字典序升序排列。

输入格式

  1. inputStr (用于构造函数或初始化的字符串,在样例中未直接体现,以 dirTreeLines 形式给出):

    • 题目中的样例输入实际上是 LeetCode 竞赛的一种输入格式,每行表示一个函数调用。
  2. dirName, fileName, name:

    • 仅包含小写字母。
    • 长度范围: [1, 100]
  3. pathName:

    • 仅包含小写字母和 /
    • 0 <= pathName.length < 1000
    • 路径中不包含 ...
    • 非空时为合法目录名,末尾可能带 /

输出格式

  • 根据每个函数的原型要求返回相应的值。最终的整体输出由评测框架完成。

样例

输入样例 1

["FileSystem", "makeDir", "makeDir", "makeDir", "listDir", "changeDir", "createFile", "makeDir", "createFile", "listDir", "changeDir"]
[[], ["dirc"], ["dirb"], ["dirc"], [], ["dirc/"], ["fileb"], ["dirb"], ["dirb"], [], ["/dirb/dirc"]]

输出样例 1

[null, true, true, false, ["dirb", "dirc"], true, true, true, false, ["dirb", "fileb"], false]

样例 1 解释

#调用内部状态/解释返回值
1FileSystem()初始化成功,当前在根目录 /null
2makeDir("dirc")/ 下创建目录 dirc,成功。true
3makeDir("dirb")/ 下创建目录 dirb,成功。true
4makeDir("dirc")目录 dirc/ 下已存在,创建失败。false
5listDir()列出 / 下内容,目录按字典序为 dirb, dirc["dirb", "dirc"]
6changeDir("dirc/")切换到 dirc 目录(末尾的 / 被忽略),成功。true
7createFile("fileb")/dirc 下创建文件 fileb,成功。true
8makeDir("dirb")/dirc 下创建目录 dirb,成功。true
9createFile("dirb")目录 dirb/dirc 下已存在,文件名冲突,创建失败。false
10listDir()列出 /dirc 下内容,目录 dirb 在前,文件 fileb 在后。["dirb", "fileb"]
11changeDir("/dirb/dirc")尝试切换到绝对路径 /dirb/dirc,但该目录不存在,失败。false
import java.util.*;

public class FileSystem {
    // --- 内部数据结构定义 ---
    private abstract static class Node {
        String name;
        public Node(String name) { this.name = name; }
    }

    private static class FileNode extends Node {
        public FileNode(String name) { super(name); }
    }

    private static class DirectoryNode extends Node {
        // TreeMap 自动按 key(文件名/目录名) 的字典序排序
        Map<String, Node> children = new TreeMap<>();
        public DirectoryNode(String name) { super(name); }
    }

    // --- FileSystem 类的成员变量 ---
    private final DirectoryNode root;
    private DirectoryNode currentNode;

    // --- 公共方法实现 ---
    public FileSystem() {
        this.root = new DirectoryNode("/");
        this.currentNode = this.root;
    }

    public boolean makeDir(String dirName) {
        if (currentNode.children.containsKey(dirName)) {
            return false;
        }
        DirectoryNode newDir = new DirectoryNode(dirName);
        currentNode.children.put(dirName, newDir);
        return true;
    }

    public boolean createFile(String fileName) {
        if (currentNode.children.containsKey(fileName)) {
            return false;
        }
        FileNode newFile = new FileNode(fileName);
        currentNode.children.put(fileName, newFile);
        return true;
    }

    public boolean changeDir(String pathName) {
        if (pathName.isEmpty()) {
            return true;
        }
        DirectoryNode targetDir = resolvePathToDirectory(pathName);
        if (targetDir != null) {
            this.currentNode = targetDir;
            return true;
        }
        return false;
    }

    public boolean remove(String name) {
        if (currentNode.children.containsKey(name)) {
            currentNode.children.remove(name);
            return true;
        }
        return false;
    }

    public List<String> listDir() {
        List<String> dirNames = new ArrayList<>();
        List<String> fileNames = new ArrayList<>();

        // TreeMap保证了遍历顺序是按key的字典序
        for (Map.Entry<String, Node> entry : currentNode.children.entrySet()) {
            if (entry.getValue() instanceof DirectoryNode) {
                dirNames.add(entry.getKey());
            } else {
                fileNames.add(entry.getKey());
            }
        }
        List<String> result = new ArrayList<>(dirNames);
        result.addAll(fileNames);
        return result;
    }

    // --- 私有辅助方法 ---
    private DirectoryNode resolvePathToDirectory(String path) {
        DirectoryNode startNode = path.startsWith("/") ? root : currentNode;
        String[] parts = path.split("/");

        DirectoryNode tempNode = startNode;
        for (String part : parts) {
            if (part.isEmpty()) {
                continue; // 处理 "a//b" 或 "/a" "/a/" 这样的情况
            }
            Node nextNode = tempNode.children.get(part);
            if (nextNode == null || nextNode instanceof FileNode) {
                return null; // 路径不存在或者是文件
            }
            tempNode = (DirectoryNode) nextNode;
        }
        return tempNode;
    }
}