problemhardood

Object-Oriented Design for an In-Memory File System

Problem

Design an in-memory file system that models files and directories, supports basic filesystem operations (create, delete, list, change directory), and keeps common metadata (timestamps, permissions, size). Provide a clean OOD view and an example skeleton implementation.

Solution

1. Requirements Analysis

Functional requirements:

  • Represent files and directories with metadata: name, extension, size, timestamps, flags (read-only, hidden, executable).
  • Support directory hierarchy (folders containing files and other folders).
  • Basic operations: create (file/folder), list contents, change directory, remove files/folders.
  • Provide a simple CLI loop for interactive commands (touch, mkdir, ls, cd, rm).

Non-functional requirements:

  • In-memory representation (no persistence) with efficient traversal and lookup in a directory.
  • Simplicity: the example focuses on clarity rather than full POSIX semantics.

2. Use Case Diagram

Actors: User (interacting via CLI or API).

Use case summary: A User issues commands to create files/folders, list directory contents, change directories, and remove files. The FileSystem maintains the current working directory and enforces directory-only operations.

graph TD
  subgraph FileSystem
  UC_Touch(Create File)
  UC_Mkdir(Create Directory)
  UC_Ls(List Contents)
  UC_Cd(Change Directory)
  UC_Rm(Remove File/Directory)
  end
  User --> UC_Touch
  User --> UC_Mkdir
  User --> UC_Ls
  User --> UC_Cd
  User --> UC_Rm

3. Class Diagram

Core classes and responsibilities:

  • File: Value object for files and directories (name, extension, size, timestamps, flags, isFolder, parent, children).
  • FileSystem: Root container with current working directory, and operations to create, list, change directory, and remove entries.
  • CLI (optional): Simple loop to parse commands and call FileSystem APIs.
classDiagram
  class File {
  +String fileName
  +String extension
  +long size
  +boolean isFolder
  +File parent
  +Set~File~ children
  +getName()
  }
  class FileSystem {
  +File root
  +File current
  +create(name, isFolder)
  +list()
  +changeDirectory(dir)
  +remove(names)
  }
  FileSystem --> File
  File --> File : children

4. Activity Diagrams

Activity: Create File/Directory

graph TD
  U[User issues create command] --> S[FileSystem validates current is directory]
  S --> C[Create File object]
  C --> A[Set parent and add to children]
  A --> R[Return success]

Activity: Change Directory

graph TD
  U[User issues cd command] --> L[Lookup child in current children]
  L --> F{Found?}
  F -- Yes --> C[Set current = child]
  F -- No --> E[Return error]

5. High-Level Code Implementation

Below are cleaned skeletons derived from the original example.

Java

import java.util.*;

public class File {
  String fileName = "";
  String extension = "";
  long size = 0;
  Date createdTime = new Date();
  Date modifiedTime = new Date();
  boolean readOnly = false;
  boolean hidden = false;
  boolean isExecutable = false;

  boolean isFolder = false;
  File parent = null;
  Set<File> children = new HashSet<>();

  public String getName() {
    return isFolder ? fileName : fileName + "." + extension;
  }

  @Override
  public String toString() {
    String appendix = isFolder ? "/" : "." + extension;
    return fileName + appendix;
  }
}

public class FileSystem {
  File root = new File();
  File current = root;

  public FileSystem() {
    root.fileName = "~";
    root.isFolder = true;
  }

  public boolean create(String name, boolean isFolder) {
    if (current.isFolder) {
      File newFile = new File();
      if (isFolder) {
        newFile.fileName = name;
      } else {
        String[] names = name.split("\\.");
        newFile.fileName = names[0];
        newFile.extension = names.length > 1 ? names[1] : "";
      }
      newFile.isFolder = isFolder;
      newFile.parent = current;
      current.children.add(newFile);
      return true;
    } else {
      System.out.println("Can only create a file under a directory");
      return false;
    }
  }

  public void list() {
    for (File file : current.children) {
      System.out.printf("%5d %40s\n", file.size, file);
    }
  }

  public boolean changeDirectory(String dir) {
    if (dir.equals("..") && current.parent != null) {
      current = current.parent;
      return true;
    }
    for (File file : current.children) {
      if (file.getName().equals(dir) && file.isFolder) {
        current = file;
        return true;
      }
    }
    return false;
  }

  public boolean remove(String[] names) {
    List<File> filesToRemove = new LinkedList<>();
    boolean deleted = false;
    for (File file : current.children) {
      for (String name : names) {
        if (file.getName().equals(name)) filesToRemove.add(file);
      }
    }
    for (File file : filesToRemove) {
      current.children.remove(file);
      deleted = true;
    }
    return deleted;
  }
}

Python

from __future__ import annotations
from dataclasses import dataclass, field
from typing import Set, Optional
from datetime import datetime

@dataclass
class File:
  file_name: str = ""
  extension: str = ""
  size: int = 0
  created_time: datetime = field(default_factory=datetime.now)
  modified_time: datetime = field(default_factory=datetime.now)
  read_only: bool = False
  hidden: bool = False
  is_executable: bool = False
  is_folder: bool = False
  parent: Optional["File"] = None
  children: Set["File"] = field(default_factory=set)

  def get_name(self) -> str:
    return self.file_name if self.is_folder else f"{self.file_name}.{self.extension}"

class FileSystem:
  def __init__(self) -> None:
    self.root = File(file_name="~", is_folder=True)
    self.current = self.root

  def create(self, name: str, is_folder: bool) -> bool:
    if not self.current.is_folder:
      print("Can only create a file under a directory")
      return False
    new_file = File()
    if is_folder:
      new_file.file_name = name
    else:
      parts = name.split('.')
      new_file.file_name = parts[0]
      new_file.extension = parts[1] if len(parts) > 1 else ''
    new_file.is_folder = is_folder
    new_file.parent = self.current
    self.current.children.add(new_file)
    return True

  def list(self) -> None:
    for f in self.current.children:
      print(f.size, f)

  def change_directory(self, dir: str) -> bool:
    if dir == '..' and self.current.parent:
      self.current = self.current.parent
      return True
    for f in self.current.children:
      if f.get_name() == dir and f.is_folder:
        self.current = f
        return True
    return False

References

Comments