Skip to content

A modern, immutable, async-first, DI-friendly abstraction of hierarchical file systems with a consistent and developer friendly API that allows seamless switching between multiple underlying file system manifestations, while also fixing and hiding the flaws and inconsistencies of the wrapped APIs.

License

Notifications You must be signed in to change notification settings

manuelroemer/Files

Repository files navigation

Caution

This project is not maintained anymore.




Files   Nuget GitHub License Nullable Reference Types Build Status

Files is a modern file system abstraction for .NET. As such, Files has the following key features:

No Tight Coupling to a Concrete File System:
Easily switch between different file system implementations, including the local machine's physical file system, an implementation using UWP's Windows.Storage API and an in-memory solution for testing! And of course, you can easily create your own implementation if necessary.

Immutable by Default:
In comparison to .NET's FileInfo/DirectoryInfo and UWP's IStorageFile/IStorageFolder, the core members of Files are immutable. In comparison to FileInfo, moving a file with File's API doesn't mutate the FileInfo.FullPath equivalent. Interacting with a file system suddenly becomes predictable!

Async First:
When working with a file system, seemingly harmless code can easily end up blocking, for example when the application encounters a large number of files or when data is stored on network drives. Files' async-first API entirely removes such problems.

Consistent API Design:
Files fixes many inconsistencies of .NET's file system APIs. Have you ever wondered why System.IO.File throws UnauthorizedAccessExceptions when a conflicting folder exists? Why System.IO.Directory throws an IOException in the same situation? Why you can move directories to the same location, but get an exception when you try the same with files? No? Well, nontheless, Files fixes all of these inconsistencies and a lot more (especially in the UWP area) and provides a thought-through API surface, starting with class design and ending with potential exceptions.

Thoroughly Tested:
Each FileSystem implementation is tested against a self-imposed specification. The tests run on 3 different OSs (Windows (Win32/UWP), Ubuntu, macOS) using both modern and legacy .NET SDKs in order to catch and fix platform-specific problems (of which there are many) and provide a consistent developer experience.

.NET Standard 2.0 and Polyfill Support:
Files targets .NET Standard 2.0 and officially supports .NET Framework. In addition, it backports several APIs which have been added to newer .NET SDKs like the System.IO.Path.Join(...) method.

Extensively Documented:
A lot of effort has been put into documenting the library with XML comments and annotating it with Nullable Reference Types.

The Files Core API

The following class diagram shows the five most important members of the Files Core API and should give a great overview about the library's design. Supporting members like enums and utility extension methods are not shown in the image.

The Files Core API

The Files Core API (v0.1.0).

Explanation of the members:

FileSystem: The central entrypoint into the API, designed with dependency injection in mind. Mainly serves as a factory for creating the other members (StoragePath, StorageFile and StorageFolder).

StoragePath: An abstraction over the file system's path behavior. Since each file system could handle paths differently, Files provides a wrapper around the raw path strings which are typically used.

StorageFile: Represents a file at a specific path and provides methods for interacting with it.

StorageFolder: Represents a folder at a specific path and provides methods for interacting with it.

Code Example

In the following, you can find two simple examples of how the Files API can be used.

// Example 1: Creating a file in a folder and writing "Hello world!" to it.
FileSystem fs = new InMemoryFileSystem();
StoragePath tempFolderPath = fs.GetPath(KnownFolder.TemporaryData);
StoragePath helloWorldPath = tempFolderPath / "Greetings" / "HelloWorld.txt";
// Note: The '/' operator joins paths and is thus equivalent to using StoragePath.Join(...).

StorageFile file = fs.GetFile(helloWorldPath);
await file.CreateRecursivelyAsync();
await file.WriteTextAsync("Hello world!");
// Example 2: Moving a folder from one location to another. Highlights what's meant by immutability.
FileSystem fs = new PhysicalFileSystem();
StorageFolder folderToMove = fs.GetFolder(KnownFolder.DocumentsLibrary / "Source");
StoragePath destinationPath = folderToMove.Path.FullPath.Parent! / "Destination";

StorageFolder movedFolder = await folderToMove.MoveAsync(destinationPath);
Console.WriteLine(folderToMove.Path); // e.g. "C:/Users/Example/Documents/Source"
Console.WriteLine(movedFolder.Path);  // e.g. "C:/Users/Example/Documents/Destination"

Note:
Please do not confuse the members above with UWP's StorageFile and StorageFolder. These two classes are completely independent of UWP and have simply been named like this (and not, for example, simply File and Folder) to prevent naming conflicts with .NETs System.IO namespace.

Installation

Files is available on NuGet. Install it via:

Install-Package <Package-Name>

--or--

dotnet add <Package-Name>

The following table displays the available packages. All packages target .NET Standard 2.0 at minimum:

📦 Package 📃 Description
Files The base package providing the API contract and abstractions. This is always required.
Files.FileSystems.Physical Provides a FileSystem implementation for the physical file system based on .NET's System.IO namespace.
Files.FileSystems.WindowsStorage Provides a FileSystem implementation for the physical file system based on UWP's Windows.Storage API.
Targets uap10.0.16299.
Files.FileSystems.InMemory Provides a configurable in-memory FileSystem implementation which is designed for testing members using the Files API. Despite being designed for testing, the implementation is fully functional, i.e. not stubbed.
Files.Specification.Tests A set of MS Test test cases which form the specification for all FileSystem implementations. These tests are used to verify that the above FileSystem packages have been implemented correctly and are, due to their potential relevance to others, made publicly available as a package.
Please note that this specific package does not abide to any versioning conventions. While minimized, breaking changes can always happen here!

Versioning

Files follows Semantic Versioning. In addition, all packages share a single version number. A (breaking) change in any package will lead to a cascading version increment in all other packages.

While this can easily lead to a high major version, it ensures that you can at a glance determine which Files packages are compatible with each other. In addition, the number of breaking changes is supposed to be kept minimal. Most will typically influence library developers (i.e. FileSystem implementers) and not the end user of the API.

License

See the LICENSE file for details.

About

A modern, immutable, async-first, DI-friendly abstraction of hierarchical file systems with a consistent and developer friendly API that allows seamless switching between multiple underlying file system manifestations, while also fixing and hiding the flaws and inconsistencies of the wrapped APIs.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages