Katkat

Implement an In-Memory File System

RipplingSoftware Engineer · Onsite

Last updated

Design and implement an in-memory file system supporting directory creation, file appending, reading, and lexicographically sorted path listings.

Implement an In-Memory File System

Design an in-memory file system to support directory and file management. Implement the FileSystem class with the following methods:

  • FileSystem(): Initializes the object with an empty root directory /.
  • ls(path: str) -> list[str]:
    • If path points to a file, returns a list containing only that file's name.
    • If path points to a directory, returns the list of file and subdirectory names in that directory, sorted in lexicographical order.
  • mkdir(path: str) -> None: Creates a new directory according to the given path. If the intermediate directories in the path do not exist, they should be created automatically.
  • add_content_to_file(file_path: str, content: str) -> None:
    • If file_path does not exist, creates that file with the given content. Intermediate directories are created if necessary.
    • If file_path already exists, appends the given content to the existing file content.
  • read_content_from_file(file_path: str) -> str: Returns the content in the file at file_path as a string.

Assumptions & Constraints

  • Paths are absolute: they always start with / and do not end with / unless the path is simply /.
  • Path components consist of lowercase English letters.
  • You will not receive invalid operations (e.g., read_content_from_file on a directory or ls on a non-existent path).
  • The total number of calls across all methods is at most 500.
  • Length of any path does not exceed 100 characters.

Example

fs = FileSystem()

# Root directory is initially empty
fs.ls("/")  # Returns []

fs.mkdir("/a/b/c")
fs.add_content_to_file("/a/b/c/d", "hello")

# ls on a directory returns child names in sorted order
fs.ls("/")        # Returns ["a"]
fs.ls("/a/b")     # Returns ["c"]

# ls on a file path returns just the file name
fs.ls("/a/b/c/d") # Returns ["d"]

# Reading file content
fs.read_content_from_file("/a/b/c/d") # Returns "hello"

# Appending content
fs.add_content_to_file("/a/b/c/d", " world")
fs.read_content_from_file("/a/b/c/d") # Returns "hello world"

Edge Cases to Consider

  • Operating on the root directory / directly.
  • Creating nested paths where multiple parent directories do not yet exist.
  • Distinguishing between an empty directory and a file with empty content.

Hints

Hint 1

Model the file system as an N-ary tree or Trie where each node can be either a directory (with child nodes) or a file (with string content).

Hint 2

Split paths by the '/' delimiter and filter out empty tokens to traverse or create nodes level by level starting from the root.

Hint 3

For the ls operation, check whether the resolved node is a file; if it is, return only the node's own name rather than its children.

Follow-up questions

  • How would you support relative paths (including '.' for current directory and '..' for parent directory)?
  • How would you implement file deletion (`rm` and `rm -r`), ensuring deleted node memory is reclaimed cleanly?
  • How would you make this file system thread-safe for concurrent read and write operations without causing severe lock contention?