OOD - In-memory File System
1. Problem Statement
Design a simple, in-memory file system that models files and directories and supports core operations: create, list, change directory, and remove. Store common metadata (name, size, timestamps, and flags like read-only/hidden/executable). Provide a clean OOD structure with minimal skeleton code.
Core goals:
- Hierarchical directories (parent → children) with simple traversal
- Basic operations (touch/mkdir/ls/cd/rm) via clear APIs
- In-memory only (no persistence), favoring simplicity over full POSIX semantics
- Keep classes small and focused:
File(metadata/tree),FileSystem(operations)
2. System Requirements
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.
3. 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 TB subgraph "File System" UC_Touch["Create File touch"] UC_Mkdir["Create Directory mkdir"] UC_Ls["List Contents ls"] UC_Cd["Change Directory cd"] UC_Rm["Remove File or Directory rm"] end User([User]) User --> UC_Touch User --> UC_Mkdir User --> UC_Ls User --> UC_Cd User --> UC_Rm style User fill:#4CAF50,color:#fff
4. 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
5. 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]
6. Java Implementation
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;
}
}
7. Python Implementation
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