FileSystem 0.4.0
See the version list below for details.
dotnet add package FileSystem --version 0.4.0
NuGet\Install-Package FileSystem -Version 0.4.0
<PackageReference Include="FileSystem" Version="0.4.0" />
paket add FileSystem --version 0.4.0
#r "nuget: FileSystem, 0.4.0"
// Install FileSystem as a Cake Addin #addin nuget:?package=FileSystem&version=0.4.0 // Install FileSystem as a Cake Tool #tool nuget:?package=FileSystem&version=0.4.0
FileSystem
An asnyc FileSystem abstraction, with decoration and in-memory/virtual support.
Installation
This package is available on NuGet.
PM> install-package FileSystem
Usage
public class Configuration
{
private readonly IFileSystem _fileSystem;
public Configuration(IFileSystem fileSystem)
{
_fileSystem = fileSystem;
}
public async Task Load()
{
using (var stream = await _fileSystem.ReadFile("config.json"))
{
//...
}
}
public async Task Save()
{
await _fileSystem.WriteFile("config.json", async stream => {
await stream.Write(/* ... */);
});
}
}
//usage:
var config = new Configuration(new PhysicalFileSystem());
Logging
As I didn't want to take a dependency on any particular logging library, there is no out of the box implementation. However, implementing your own only takes a few lines of code, making use of the EventingFileSystem
class. For example, logging everything as Debug with Serilog:
public class LoggingFileSystem : EventingFileSystem
{
public LoggingFileSystem(IFileSystem inner) : base(inner)
{
HandleEvent = message =>
{
Log.Debug($"{message}: {{@event}}", message);
return Task.CompletedTask;
};
}
}
Each event emitted by the EventingFileSystem
has a reasonable .ToString
implementaiton, so you can just write Console.WriteLine(message.ToString())
if you wish.
Decoration
For ease of implementing, FileSystem supplies a FileSystemDecorator
class, which implements all IFileSystem
methods as virtual calls to an inner IFileSystem
.
For example, an encrypting filesystem could be implemented by just overriding a few methods:
public class EncryptingFileSystem : FileSystemDecorator
{
private readonly ICrypto _crypto;
public EncryptingFileSystem(IFileSystem inner, ICrypto crypto) : base(inner)
{
_crypto = crypto;
}
public override async Task<Stream> ReadFile(string path)
{
return await _crypto.DecryptStream(await base.ReadFile(path));
}
public override async Task WriteFile(string path, Func<Stream, Task> write)
{
await base.WriteFile(path, async stream =>
{
using (var encrypted = await _crypto.Encrypt(async cryptoStream => await write(cryptoStream)))
{
await encrypted.CopyToAsync(stream);
}
});
}
public override Task AppendFile(string path, Func<Stream, Task> write)
{
throw new NotSupportedException("You cannot append to an encrypted file. Try reading, and the writing the whole file.");
}
}
Testing
The easiest way of testing code using an IFileSystem
dependency is to use the InMemoryFileSystem
, which will behave the same as the physical file system.
var fileSystem = new InMemoryFileSystem();
var sut = new TestClass(fileSystem);
sut.Execute();
fileSystem
.ReadLines("./the/file.txt")
.ShouldBe(new[] { "first", "second", "third" });
Alternatly, if you want to assert on something written to a stream, e.g. on a .AppendFile()
call, you can do it manually (this example using NSubstitute):
var ms = new MemoryStream();
var fileSystem = Substitute.For<IFileSystem>();
fileSystem
.AppendFile("wat", Arg.Do<Func<Stream, Task>>(func => func(ms).Wait()))
.Returns(Task.CompletedTask);
fileSystem.AppendFile("wat", async stream => {
await stream.WriteAsync(new byte[] { 1, 2, 3 }, 0, 3);
});
ms.ToArray().ShouldBe(new byte[] { 1, 2, 3});
Or if you want to capture many streams, you can use the provided StreamCapture
class:
var streams = new StreamCapture();
var fileSystem = Substitute.For<IFileSystem>();
fileSystem
.AppendFile("wat", Arg.Do<Func<Stream, Task>>(streams.Capture))
.Returns(Task.CompletedTask);
fileSystem.AppendFile("wat", async stream => {
await stream.WriteAsync(new byte[] { 1, 2, 3 }, 0, 3);
});
streams.Last.ToArray().ShouldBe(new byte[] { 1, 2, 3});
To do
- Caching FileSystem
- Read caching I guess
- pluggable caching strategies
- Commitable FileSystem (call
.Commit()
to flush writes to disk.) - Case(In)Sensitive FileSystem?
- Not sure how this would work
- ReadFile would ListFiles first, then find the right mapping perhaps?
- S3FileSystem
- Separate package I guess
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.