Design an in-memory file system to simulate the following functions:
ls
: Given a path in string format. If it is a file path, return a list that only contains this file's name. If it is a directory path, return the list of file and directory names in lexicographical order.mkdir
: Given a directory path that does not exist, you should make a new directory. If the middle directories in the path do not exist either, you should create them as well. This function has void return type.addContentToFile
: Given a file path and content in string format. If the file doesn't exist, you should create that file. Then append the given content to that file. This function has void return type.readContentFromFile
: Given a file path, return the content in string format.Example:
Input: ["FileSystem","ls","mkdir","addContentToFile","ls","readContentFromFile"] [[],["/"],["/a/b/c"],["/a/b/c/d","hello"],["/"],["/a/b/c/d"]] Output: [null,[],null,null,["a"],"hello"] Explanation: FileSystem fileSystem = new FileSystem(); fileSystem.ls("/"); // return [] fileSystem.mkdir("/a/b/c"); fileSystem.addContentToFile("/a/b/c/d", "hello"); fileSystem.ls("/"); // return ["a"] fileSystem.readContentFromFile("/a/b/c/d"); // return "hello"
Note:
'/'
.'/..'
.1
and 300
.100
.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
Let's create a very simple file system in our computer's memory. A brute force method would involve directly searching and creating the files and folders whenever needed, without any clever organization.
Here's how the algorithm would work step-by-step:
class FileSystem:
def __init__(self):
self.root = {}
def create_file(self, file_path, content):
path_components = file_path.split('/')
current_directory = self.root
for i in range(1, len(path_components) - 1):
component = path_components[i]
if component not in current_directory:
return False
current_directory = current_directory[component]
file_name = path_components[-1]
# Check if file exists already
if file_name in current_directory:
return False
current_directory[file_name] = content
return True
def create_directory(self, directory_path):
path_components = directory_path.split('/')
current_directory = self.root
for i in range(1, len(path_components)):
component = path_components[i]
# Directory exists, creation fails
if component in current_directory:
return False
current_directory[component] = {}
current_directory = current_directory[component]
return True
def read_file(self, file_path):
path_components = file_path.split('/')
current_directory = self.root
for i in range(1, len(path_components) - 1):
component = path_components[i]
if component not in current_directory:
return None
current_directory = current_directory[component]
file_name = path_components[-1]
if file_name not in current_directory:
return None
# Return content if file is found
return current_directory[file_name]
def list_contents(self, directory_path):
path_components = directory_path.split('/')
current_directory = self.root
for i in range(1, len(path_components)):
component = path_components[i]
if component not in current_directory:
return None
current_directory = current_directory[component]
# Returns all immediate children
return list(current_directory.keys())
We'll simulate a simplified file system in memory. The core idea is to represent the file system structure using a tree-like organization, where each node can be either a directory or a file.
Here's how the algorithm would work step-by-step:
class File:
def __init__(self, name, content):
self.name = name
self.content = content
class Directory:
def __init__(self, name):
self.name = name
self.children = {}
class FileSystem:
def __init__(self):
# Initialize the root directory for the file system.
self.root = Directory("/")
def create_directory(self, path):
path_parts = path.split("/")
current_directory = self.root
for part in path_parts[1:]:
if not part:
continue
if part not in current_directory.children:
current_directory.children[part] = Directory(part)
current_directory = current_directory.children[part]
def create_file(self, path, content):
path_parts = path.split("/")
file_name = path_parts[-1]
current_directory = self.root
for part in path_parts[1:-1]:
if not part:
continue
if part not in current_directory.children:
# Create intermediate directories if they don't exist.
current_directory.children[part] = Directory(part)
current_directory = current_directory.children[part]
current_directory.children[file_name] = File(file_name, content)
def read_file(self, path):
path_parts = path.split("/")
file_name = path_parts[-1]
current_directory = self.root
for part in path_parts[1:-1]:
if not part:
continue
current_directory = current_directory.children[part]
if file_name in current_directory.children:
return current_directory.children[file_name].content
else:
return None
def list_directory(self, path):
path_parts = path.split("/")
current_directory = self.root
for part in path_parts[1:]:
if not part:
continue
# Navigate to the target directory.
if part in current_directory.children:
current_directory = current_directory.children[part]
else:
return []
# Extract the names of all children (files and directories).
return list(current_directory.children.keys())
Case | How to Handle |
---|---|
Null or empty path | Return error or handle gracefully if the path is null or empty, depending on the operation (create, delete, read). |
Path contains consecutive slashes '//' | Normalize the path by collapsing consecutive slashes into a single slash. |
Path is too long exceeding the maximum file system path length | Return an error indicating the path is too long. |
Creating a file or directory with the same name as an existing one. | Return an error if attempting to create a file/directory with the same name as an existing one, or overwrite depending on specification. |
Deleting a non-empty directory. | Implement recursive delete if necessary, or return error if non-empty directories cannot be deleted directly. |
Reading from a file that does not exist or a directory | Return an error indicating that the file does not exist or it is a directory. |
Writing to a file exceeding maximum file size | Return an error or handle file truncation depending on specification. |
Insufficient memory to create a new file or directory. | Return an error indicating insufficient memory. |