{"id":15649624,"url":"https://github.com/manuelroemer/files","last_synced_at":"2025-04-13T05:37:47.835Z","repository":{"id":37848600,"uuid":"246427949","full_name":"manuelroemer/Files","owner":"manuelroemer","description":"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.","archived":false,"fork":false,"pushed_at":"2024-08-30T17:36:16.000Z","size":488,"stargazers_count":40,"open_issues_count":15,"forks_count":4,"subscribers_count":3,"default_branch":"dev","last_synced_at":"2025-04-13T05:37:41.584Z","etag":null,"topics":["async","consistency","cross-platform","dependency-injection","di","file","fs","in-memory","io","mocks","system","testing","uwp","vfs"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/manuelroemer.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-03-10T23:13:32.000Z","updated_at":"2025-02-16T15:26:41.000Z","dependencies_parsed_at":"2024-10-23T01:17:15.412Z","dependency_job_id":"08407c67-c417-49e1-b39b-a1c78fffc3a0","html_url":"https://github.com/manuelroemer/Files","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/manuelroemer%2FFiles","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/manuelroemer%2FFiles/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/manuelroemer%2FFiles/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/manuelroemer%2FFiles/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/manuelroemer","download_url":"https://codeload.github.com/manuelroemer/Files/tar.gz/refs/heads/dev","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248670506,"owners_count":21142897,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async","consistency","cross-platform","dependency-injection","di","file","fs","in-memory","io","mocks","system","testing","uwp","vfs"],"created_at":"2024-10-03T12:30:33.676Z","updated_at":"2025-04-13T05:37:47.788Z","avatar_url":"https://github.com/manuelroemer.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003e [!CAUTION]\n\u003e This project is not maintained anymore.\n\n\u003cbr/\u003e\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n\n# \u003cimg src=\"assets/Icon64x64.png\" width=\"48\" height=\"48\" /\u003e Files \u0026nbsp; [![Nuget](https://img.shields.io/nuget/v/Files)](https://www.nuget.org/packages/Files) [![GitHub License](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE) ![Nullable Reference Types](https://img.shields.io/badge/%E2%9C%93-Nullable%20Reference%20Types-success) [![Build Status](https://dev.azure.com/ManuelRoemer/Files/_apis/build/status/Files%20CI?branchName=master)](https://dev.azure.com/ManuelRoemer/Files/_build/latest?definitionId=20\u0026branchName=master)\n\nFiles is a **modern file system abstraction** for .NET. As such, Files has the following key features:\n\n✨ **No Tight Coupling to a Concrete File System**:\u003cbr/\u003e\nEasily switch between **different file system implementations**, including the local machine's\n**physical file system**, an implementation using **UWP**'s `Windows.Storage` API and an\n**in-memory** solution for **testing**!\nAnd of course, you can easily create **your own** implementation if necessary.\n\n\n✨ **Immutable by Default**:\u003cbr/\u003e\nIn comparison to .NET's `FileInfo`/`DirectoryInfo` and UWP's `IStorageFile`/`IStorageFolder`,\nthe core members of Files are immutable. In comparison to `FileInfo`, moving a file with File's\nAPI doesn't mutate the `FileInfo.FullPath` equivalent.\nInteracting with a file system suddenly becomes predictable!\n\n✨ **Async First**:\u003cbr/\u003e\nWhen working with a file system, seemingly harmless code can easily end up blocking, for example\nwhen the application encounters a large number of files or when data is stored on network drives.\nFiles' async-first API entirely removes such problems.\n\n✨ **Consistent API Design**:\u003cbr/\u003e\nFiles fixes many inconsistencies of .NET's file system APIs.\nHave you ever wondered why `System.IO.File` throws `UnauthorizedAccessException`s when a conflicting folder exists?\nWhy `System.IO.Directory` throws an `IOException` in the same situation?\nWhy you can move directories to the same location, but get an exception when you try the same with files?\n*No?* Well, nontheless, Files **fixes all of these inconsistencies** and **a lot more** (especially\nin the UWP area) and provides a thought-through API surface, starting with class design and ending\nwith potential exceptions.\n\n✨ **Thoroughly Tested**:\u003cbr/\u003e\nEach `FileSystem` implementation is tested against a self-imposed specification.\nThe tests run on **3 different OSs** (Windows (Win32/UWP), Ubuntu, macOS) using both modern and legacy\n.NET SDKs in order to catch and fix platform-specific problems (of which there are\nmany) and provide a **consistent developer experience**.\n\n✨ **.NET Standard 2.0 and Polyfill Support**:\u003cbr/\u003e\nFiles targets .NET Standard 2.0 and officially supports .NET Framework.\nIn addition, it backports several APIs which have been added to newer .NET SDKs like the\n`System.IO.Path.Join(...)` method.\n\n✨ **Extensively Documented**:\u003cbr/\u003e\nA lot of effort has been put into documenting the library with **XML comments** and annotating it with\n**Nullable Reference Types**.\n\n\n\n## The Files Core API\n\nThe following class diagram shows the **five most important members** of the Files Core API and should\ngive a great overview about the library's design.\nSupporting members like enums and utility extension methods are not shown in the image.\n\n![The Files Core API](./doc/assets/core-api-overview-class-diagram.png)\n\u003e The Files Core API (`v0.1.0`).\n\nExplanation of the members:\n\n**`FileSystem`**:\nThe central entrypoint into the API, designed with dependency injection in mind.\nMainly serves as a factory for creating the other members (`StoragePath`, `StorageFile` and `StorageFolder`).\n\n**`StoragePath`**:\nAn abstraction over the file system's path behavior. Since each file system could handle paths differently,\nFiles provides a wrapper around the raw path strings which are typically used.\n\n**`StorageFile`**:\nRepresents a file at a specific path and provides methods for interacting with it.\n\n**`StorageFolder`**:\nRepresents a folder at a specific path and provides methods for interacting with it.\n\n\n### Code Example\n\nIn the following, you can find two simple examples of how the Files API can be used.\n\n```csharp\n// Example 1: Creating a file in a folder and writing \"Hello world!\" to it.\nFileSystem fs = new InMemoryFileSystem();\nStoragePath tempFolderPath = fs.GetPath(KnownFolder.TemporaryData);\nStoragePath helloWorldPath = tempFolderPath / \"Greetings\" / \"HelloWorld.txt\";\n// Note: The '/' operator joins paths and is thus equivalent to using StoragePath.Join(...).\n\nStorageFile file = fs.GetFile(helloWorldPath);\nawait file.CreateRecursivelyAsync();\nawait file.WriteTextAsync(\"Hello world!\");\n```\n\n```csharp\n// Example 2: Moving a folder from one location to another. Highlights what's meant by immutability.\nFileSystem fs = new PhysicalFileSystem();\nStorageFolder folderToMove = fs.GetFolder(KnownFolder.DocumentsLibrary / \"Source\");\nStoragePath destinationPath = folderToMove.Path.FullPath.Parent! / \"Destination\";\n\nStorageFolder movedFolder = await folderToMove.MoveAsync(destinationPath);\nConsole.WriteLine(folderToMove.Path); // e.g. \"C:/Users/Example/Documents/Source\"\nConsole.WriteLine(movedFolder.Path);  // e.g. \"C:/Users/Example/Documents/Destination\"\n```\n\n\u003e ℹ **Note:**\u003cbr/\u003e\n\u003e Please do not confuse the members above with UWP's `StorageFile` and `StorageFolder`.\n\u003e These two classes are completely independent of UWP and have simply been named like this (and not,\n\u003e for example, simply `File` and `Folder`) to prevent naming conflicts with .NETs `System.IO` namespace.\n\n\n\n## Installation\n\nFiles is available on NuGet. Install it via:\n\n```\nInstall-Package \u003cPackage-Name\u003e\n\n--or--\n\ndotnet add \u003cPackage-Name\u003e\n```\n\nThe following table displays the available packages. All packages target **.NET Standard 2.0** at minimum:\n\n| 📦 Package | 📃 Description |\n| --- | --- |\n| [`Files`](https://www.nuget.org/packages/Files)  | The base package providing the API contract and abstractions. This is always required. |\n| [`Files.FileSystems.Physical`](https://www.nuget.org/packages/Files.FileSystems.Physical) | Provides a `FileSystem` implementation for the physical file system based on .NET's `System.IO` namespace. |\n| [`Files.FileSystems.WindowsStorage`](https://www.nuget.org/packages/Files.FileSystems.WindowsStorage) | Provides a `FileSystem` implementation for the physical file system based on UWP's `Windows.Storage` API.\u003cbr/\u003e**Targets `uap10.0.16299`.** |\n| [`Files.FileSystems.InMemory`](https://www.nuget.org/packages/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. |\n| [`Files.Specification.Tests`](https://www.nuget.org/packages/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.\u003cbr/\u003e**Please note that this specific package does not abide to any versioning conventions. While minimized, breaking changes can always happen here!** |\n\n\n\n## Versioning\n\nFiles follows Semantic Versioning. In addition, all packages share a single version number.\nA (breaking) change in any package will lead to a cascading version increment in all other packages.\n\nWhile this can easily lead to a high major version, it ensures that you can at a glance determine\nwhich Files packages are compatible with each other.\nIn addition, the number of breaking changes is supposed to be kept minimal. Most will typically\ninfluence library developers (i.e. `FileSystem` implementers) and not the end user of the API.\n\n\n\n## License\n\nSee the [LICENSE](./LICENSE) file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmanuelroemer%2Ffiles","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmanuelroemer%2Ffiles","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmanuelroemer%2Ffiles/lists"}