Framework
xoofx/zio avatar
xoofx/zio

Zio: a filesystem abstraction layer for .NET with real locking semantics

A cross-platform abstract/virtual filesystem framework with many built-ins filesystems for .NET

938 stars66 forksC#BSD-2-Clause

At a glance

What is it?
Zio gives .NET code a single IFileSystem interface over physical disks, in-memory storage and zip archives, with normalised paths through UPath, file watching and async APIs on net10.0. It is aimed at tools that need to run against a real disk, a temporary store or an archive without branching on the environment.
Who is it for?
Zio fits a .NET tool or test suite that must behave the same whether it reads a real directory, a scratch area or a zip archive, and it fits libraries that want atomic replace operations without writing their own locking. It does not fit a project that only ever touches one real disk, since System.IO already covers that, and it does not fit a team that cannot move to net10.0 if it needs the async surface.
Can I use it commercially?
Yes. BSD-2-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 4 days ago.
What is it written in?
Mainly C#, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One interface over disks, memory and archives

Zio is described as a cross-platform abstract or virtual filesystem framework for .NET, and the core promise is in the feature list: an API providing all the operations offered by the regular System.IO API, for example File.Move and Directory.Delete, with the option of atomic filesystem operations such as File.Replace. The abstraction is a single interface, IFileSystem, and the built-in implementations cover three quite different storage backends. PhysicalFileSystem reaches the real disks, directories and folders. MemoryFileSystem holds a filesystem in RAM, aiming to be 100 percent compatible with a true PhysicalFileSystem including the exceptions it throws, which is the part that makes it usable as a test double rather than a toy. ZipArchiveFileSystem is a wrapper around the .NET ZipArchive class and works in both case sensitive and case insensitive mode. The audience is code that has to be storage agnostic, typically tooling, build systems and test harnesses, rather than an application with one known filesystem.

UPath makes every path look the same

All paths are normalised through a lightweight uniform path struct called UPath, and this is where the library earns its keep on Windows. The README describes PhysicalFileSystem on Windows as working like on a Windows Subsystem Linux, remapping drives to a mount directory, so a path such as /mnt/c/Windows is equivalent to C:\Windows. That single decision removes the branch in your code that checks the platform before touching a path. The same struct is used by every filesystem, so a path handed to a memory filesystem or a zip filesystem has the same shape as one handed to the physical one. Using it looks ordinary:

csharp
var fs = new PhysicalFileSystem();
foreach(var dir in fs.EnumerateDirectories("/mnt/c"))
{
    // ...
}

There is also a higher level API above the file and directory primitives, with FileSystemEntry, FileEntry and DirectoryEntry offering an API similar to FileSystemInfo, FileInfo and DirectoryInfo, which is where the .NET developers who are used to the System.IO object model will feel at home.

The memory filesystem takes locking seriously

MemoryFileSystem is more than a dictionary with a path key. The README lists efficient concurrency through a per node locking mechanism, where a node is a file or a directory, and a safe hierarchical locking strategy that follows the Unix kernel recommendations for directory locking. It also supports FileShare.Read, FileShare.Write and FileShare.ReadWrite, and it internally supports the atomic operations such as File.Replace. This is the difference between an in-memory filesystem that a test suite can trust and one that deadlocks under parallel test execution. If you have ever had a test suite that passed alone and hung under parallel execution because the fake filesystem had no locking discipline, this is the specific problem Zio addresses. The compatibility claim cuts both ways, though: because the in-memory filesystem aims to reproduce the exceptions of the physical one, your code has to handle them, which will expose error handling that a naive fake would have hidden.

Mount, sub, aggregate and read-only are built from the same parts

The three concrete filesystems are the base, and Zio composes them into more complex ones. AggregateFileSystem provides a read-only filesystem that aggregates several filesystems and offers a merged view of them, which is how you present a set of sources as one tree. MountFileSystem mounts different filesystems at a specific mount point name. SubFileSystem exposes a sub-folder of another filesystem as if it were the root directory, which is convenient for handing a library a working directory. ReadOnlyFileSystem wraps another filesystem in read-only mode so that a component cannot accidentally write. None of these require you to implement IFileSystem yourself, and the file watcher is available across the built-in filesystems through the IFileSystem.Watch method and the IFileSystemWatcher interface, including the aggregates and the memory filesystem. Watching a virtual filesystem is what makes the abstraction complete for build tooling, where a change in a source tree should trigger a rebuild regardless of where that tree lives.

Async APIs exist only on net10.0

The target frameworks are netstandard2.0, netstandard2.1 and net8.0 or later, and the async story is layered on top of that rather than being part of the base package. The README states that net10.0 async APIs are provided via generated file-system types and IAsyncEnumerable enumeration and search helpers, with generated async types such as MemoryFileSystemAsync. In other words, if your project targets net10.0, you get an async surface with generated types and enumerable-based search; if you are on net8.0 or netstandard, you use the synchronous API. The generation step is worth noting because it means the async types follow the same shape as the synchronous ones rather than being a hand-written parallel design, but it also means the async names are not part of the same interface and need their own type in your code. The practical consequence for an adoption decision is that the async benefit arrives with a framework version bump, not with a package upgrade.

Building Zio needs Visual Studio 2022 and the .NET 10 SDK

The build requirement is specific and explained. The README says that to build Zio you need Visual Studio 2022 with the latest .NET 10 SDK, specifically so that the net10.0 async target can compile. The library itself is distributed on NuGet as Zio, and the documentation is not on a separate site but in the repository, in the doc folder. The source lives under src, and the repository also carries AGENTS.md and CLAUDE.md for assistant workflows, an .alta directory and a .github directory for CI. The licence is BSD-Clause 2, stated in the README and in a license.txt file at the root, which is a permissive licence that imposes few obligations on a team embedding it in an internal tool. The release numbering is plain, with 0.23.0 in June 2026, 0.24.0 later the same month and 0.25.0 in October 2026, so the project is pre-1.0 and the API surface may still move between minor versions.

Editorial conclusion

Zio fits a .NET tool or test suite that must behave the same whether it reads a real directory, a scratch area or a zip archive, and it fits libraries that want atomic replace operations without writing their own locking. It does not fit a project that only ever touches one real disk, since System.IO already covers that, and it does not fit a team that cannot move to net10.0 if it needs the async surface. Verify first that the file and directory operations you rely on are implemented by the filesystem you plan to use, particularly for the in-memory and zip implementations, then check that the exception behaviour of MemoryFileSystem matches what your code catches. The licence field on the repository says BSD-2-Clause, release 0.25.0 was published on 2026-10-19, and the last push was on 2026-10-19.

Frequently asked questions

What is Zio and what does it abstract?

Zio is a filesystem abstraction for .NET built around the IFileSystem interface, offering the operations of the regular System.IO API such as File.Move and Directory.Delete, and supporting atomic operations like File.Replace. Built-in implementations cover physical disks, an in-memory filesystem and zip archives, and they can be composed with mount, sub-folder, aggregate and read-only wrappers.

What is UPath and why does it matter on Windows?

UPath is a lightweight struct through which all paths are normalised, so paths look the same on every platform and filesystem. On Windows, PhysicalFileSystem remaps drives to mount directories in the WSL style, so /mnt/c/Windows is equivalent to C:\Windows.

Is the in-memory filesystem safe for concurrent tests?

The README says MemoryFileSystem aims to be 100 percent compatible with a true PhysicalFileSystem including exceptions, and it supports efficient concurrency with a per node locking mechanism plus a hierarchical locking strategy following Unix kernel recommendations for directory locking. It also supports FileShare.Read, FileShare.Write and FileShare.ReadWrite.

Does Zio support async file operations?

Yes, on net10.0. The async APIs come through generated file-system types such as MemoryFileSystemAsync and IAsyncEnumerable enumeration and search helpers. The base package targets netstandard2.0, netstandard2.1 and net8.0 or later.

Under which licence is Zio released?

The licence field on the repository says BSD-2-Clause, and the README states that the software is released under the BSD-Clause 2 licence with a license.txt file in the repository root.

Official sources

  1. Issues
  2. License: BSD-2-Clause
  3. README
  4. Releases
  5. xoofx/zio on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/xoofx-zio.svg)](https://hysenlabs.com/projects/xoofx-zio)

Was this useful?