# Usage ## Quick Start ### Create a Root Filesystem ```csharp using System.IO; using VirtualFS; using VirtualFS.Implementation; using VirtualFS.Memory; using VirtualFS.Physical; var root = new RootFileSystem(); var physical = new PhysicalFileSystem(new DirectoryInfo("/srv/site")); var generated = new MemoryFileSystem { Priority = FileSystemMountPriority.High }; root.Mount(physical, "/"); root.Mount(generated, "/"); ``` In this setup: - files present in `generated` can override files from `physical` - reads are resolved through the root - writes go to the writable backend chosen for the path ## Creating and Reading Files ```csharp var file = root.Root.FileCreate("hello.txt"); file.WriteAllText("Hello from VirtualFS"); string text = root.GetFile("/hello.txt").ReadAllText(); ``` ## Working Inside a Mounted Subtree ```csharp root.Mount(new MemoryFileSystem(), "/cache/"); var cacheDir = root.GetDirectory("/cache/"); cacheDir.Create("images"); cacheDir.GetDirectory("images/").FileCreate("thumb.txt").WriteAllText("ok"); ``` ## Overlay Example ```csharp using System.IO; using VirtualFS; using VirtualFS.Compressed; using VirtualFS.Implementation; using VirtualFS.Physical; var root = new RootFileSystem(); var baseAssets = new ZipReadFileSystem(System.IO.File.OpenRead("base-assets.zip")) { Priority = FileSystemMountPriority.Low }; var overrides = new PhysicalFileSystem(new DirectoryInfo("./overrides")) { Priority = FileSystemMountPriority.High }; root.Mount(baseAssets, "/assets/"); root.Mount(overrides, "/assets/"); ``` Reads under `/assets/` prefer files from `./overrides`, then fall back to the ZIP. ## Enumerating Entries ```csharp foreach (var entry in root.Root.GetEntries()) { Console.WriteLine($"{entry.FullPath} readonly={entry.IsReadOnly}"); } ``` You can also enumerate only files or only directories: - `GetFiles()` - `GetDirectories()` All enumeration methods support an optional regular-expression filter. ## Using `Directory` Common operations: - `GetEntries()` - `GetFiles()` - `GetDirectories()` - `Exists(name)` - `GetEntry(name)` - `GetFile(name)` - `GetDirectory(name)` - `Create(name)` - `FileCreate(name)` - `Delete(recursive)` Example: ```csharp var dir = root.GetDirectory("/content/"); if (!dir.Exists("images/")) dir.Create("images"); var imageDir = dir.GetDirectory("images/"); ``` ## Using `File` Common operations: - `OpenRead()` - `OpenWrite()` - `ReadAllBytes()` - `ReadAllLines()` - `ReadAllText()` - `WriteAllBytes()` - `WriteAllLines()` - `WriteAllText()` - `AppendAllBytes()` - `AppendAllLines()` - `AppendAllText()` - `Delete()` Example: ```csharp var file = root.GetFile("/config/appsettings.json"); var text = file.ReadAllText(); ``` ## `forceLocal` Many `Directory` and `File` instance methods accept `forceLocal`. Use it when: - you explicitly want to bypass the root overlay behavior - you want to operate only inside the backend that produced the entry Example: ```csharp var entry = root.GetFile("/assets/logo.png"); using var localStream = entry.OpenRead(forceLocal: true); ``` ## Path Examples ```csharp Path dir = "/docs/"; Path file = dir + "readme.txt"; // "/docs/readme.txt" Path parent = ((Path)"/docs/api/").Parent; // "/docs/" ``` Normalization: - `"/a/./b.txt"` becomes `"/a/b.txt"` - `"/a/b/../c.txt"` becomes `"/a/c.txt"` ## Copy, Move, Rename Available on `IFileSystem`: - `Copy` - `Move` - `ReName` Notes: - copy and move may work across different mounted backends - cross-backend operations may be slower - directory destinations are expected to be directory paths ## Unmounting `Umount` succeeds only if the filesystem is not busy. That means: - open file streams must be closed first - callers should use `using` or explicit disposal Example: ```csharp using (var stream = root.GetFile("/data/report.txt").OpenRead()) { // use stream } root.Umount(someFs); ```