Skip to content

Quick Start

Gustavo Viana edited this page Aug 7, 2026 · 9 revisions

Quick Start

Install

dotnet add package FileHub                      # core (Local + Memory)
dotnet add package FileHub.DependencyInjection  # MS.Extensions.DI helpers
dotnet add package FileHub.AmazonS3             # AWS S3 driver
dotnet add package FileHub.OracleObjectStorage  # OCI driver
dotnet add package FileHub.Ftp                  # FTP driver (FluentFTP)

Targets netstandard2.0;net8.0. Core has zero external dependencies.

Register with DI (recommended)

using FileHub.DependencyInjection;
using FileHub.Local;

services.AddFileHub<ILocalFileHub>(sp => new LocalFileHub(@"C:\data"));

Then inject IFileHub (or the driver-typed ILocalFileHub) anywhere:

public class ReportService(IFileHub hub)
{
    public void Save(string name, string body)
        => hub.Root.CreateFile(name).SetText(body);
}

Backend-agnostic consumer code, driver decided at composition root. Swap to MemoryFileHub in tests, AmazonS3FileHub in prod — no service change. More patterns: Dependency injection.

Or construct directly

For one-off scripts, console apps, or library code that doesn't run under a DI container:

using FileHub.Local;

var hub = new LocalFileHub(@"C:\data");
// hub.Root is the sandbox. Nothing outside C:\data is reachable.

Root is a DirectoryEntry — everything else is reached from here.

Files

// Create
var file = hub.Root.CreateFile("hello.txt");
file.SetText("hi");

// Nested path — auto-creates intermediate directories
hub.Root.CreateFile("reports/2026/q1.pdf").SetBytes(bytes);

// Read
var text  = hub.Root.OpenFile("hello.txt").ReadAllText();
var bytes = hub.Root.OpenFile("payload.dat").ReadAllBytes();

// Existence — file vs directory probes are separate
if (hub.Root.FileExists("hello.txt"))      { /* ... */ }
if (hub.Root.DirectoryExists("reports"))   { /* ... */ }

// Streams
using var write = hub.Root.CreateFile("big.log").GetWriteStream();
using var read  = hub.Root.OpenFile("big.log").GetReadStream();

// Non-throwing open
if (hub.Root.TryOpenFile("maybe.txt", out var f)) { /* ... */ }

// Async non-throwing open returns a tuple
var (maybe, exists) = await hub.Root.TryOpenFileAsync("maybe.txt", ct);

// Open-or-create
var cfg = hub.Root.OpenFile("config.json", createIfNotExists: true);

Directories

// Single segment
var logs = hub.Root.CreateDirectory("logs");

// Nested path — works on every driver
var target = hub.Root.CreateDirectory("2026/01/invoices");

// Non-throwing open
if (hub.Root.TryOpenDirectory("2026/01", out var jan)) { /* ... */ }

On cloud drivers the whole nested path resolves in a single API call — one PUT to create, one LIST to open.

List, rename, move, copy, delete

foreach (var f in hub.Root.GetFiles("*.log"))
    Console.WriteLine($"{f.Name}: {f.Length} bytes");

var file = hub.Root.OpenFile("report.pdf");

file.Rename("report-final.pdf");                                        // leaf name only — no '/' or '\'
file.MoveTo(hub.Root.CreateDirectory("archive"), "report-final.pdf");   // throws if the target name is taken
file.CopyTo("report-final.copy.pdf");                                   // throws if the copy name is taken
file.Delete();                                                         // idempotent — no-op if already gone

hub.Root.DeleteIfExists("maybe.txt");
hub.Root.OpenDirectory("old").Delete(recursive: true);  // non-empty dir needs recursive: true

Pagination options and caveats: Usage → Pagination.

Async

Every sync method has an async sibling with a CancellationToken:

var file = await hub.Root.CreateFileAsync("data.json", ct);
await file.SetTextAsync("{}", cancellationToken: ct);
var json = await file.ReadAllTextAsync(ct);

On net8.0, async listing yields one item at a time:

await foreach (var f in hub.Root.GetFilesAsync("*.log"))
    Console.WriteLine(f.Name);

Read-only wrapping

var ro = hub.Root.OpenDirectory("config").AsReadOnly();

ro.OpenFile("settings.json").ReadAllText();  // OK
ro.CreateFile("new.txt");                    // FileHubException

Swap drivers

Consumer code depends on IFileHub / DirectoryEntry — the driver is a constructor detail:

IFileHub hub = isTest
    ? new MemoryFileHub()
    : new LocalFileHub(@"C:\data");

void WriteReport(DirectoryEntry dir, string body)
    => dir.CreateFile("report.txt").SetText(body);

WriteReport(hub.Root, "hello");

Next

Clone this wiki locally