File System File System
File System File System
DocFX + Singulink = ♥

Search Results for

    Getting Started

    Overview

    Singulink.IO.FileSystem provides strongly-typed file and directory paths together with reliable, cross-platform file system access for .NET. Compared to System.IO, it eliminates entire categories of bugs (silent path modification, file/directory confusion, inconsistent exceptions, cross-platform mismatches) by encoding intent in the type system and making parsing explicit and separate from I/O.

    This article walks you through installation, the core concepts and a small end-to-end example. From here you can branch off into the rest of the guides for in-depth coverage of any topic.

    Installation

    Install the package from NuGet:

    dotnet add package Singulink.IO.FileSystem
    

    Supported runtimes: .NET 8.0+

    All public types live under the Singulink.IO namespace.

    Core Concepts

    The library is built around four ideas:

    1. Paths are strongly typed. A path is never just a string. It is one of four concrete interfaces: IAbsoluteFilePath, IAbsoluteDirectoryPath, IRelativeFilePath or IRelativeDirectoryPath.
    2. Parsing is separate from I/O. Path strings are validated and converted into path objects up-front. Once you have a path object, the I/O API surface is small and predictable.
    3. File system operations require absolute paths. Relative paths can be combined, navigated and converted but cannot directly access the file system. This forces you to make explicit what a relative path is relative to.
    4. No silent path modification. The library never trims, drops or "cleans up" the named segments of a path. Trailing dots, leading spaces and reserved device names are either rejected (default) or preserved exactly (when explicitly opted in).

    The Path Hierarchy

    Every concrete path is one of these four leaf interfaces:

    Path kind Implements
    IAbsoluteFilePath IAbsolutePath + IFilePath
    IAbsoluteDirectoryPath IAbsolutePath + IDirectoryPath
    IRelativeFilePath IRelativePath + IFilePath
    IRelativeDirectoryPath IRelativePath + IDirectoryPath

    IAbsolutePath and IRelativePath capture the absolute/relative axis; IFilePath and IDirectoryPath capture the file/directory axis. All of them extend IPath. Each concrete path inherits members from both axes, and most of your code will work directly with one of the four leaf interfaces. See Path Types for the full member breakdown.

    A 30-Second Tour

    Parse a Path

    using Singulink.IO;
    
    IAbsoluteFilePath configFile = FilePath.ParseAbsolute(@"C:\Apps\MyApp\config.json");
    IRelativeFilePath relativeLog = FilePath.ParseRelative("logs/today.log");
    

    Combine Paths

    IAbsoluteDirectoryPath appBase = DirectoryPath.GetAppBase();
    IAbsoluteFilePath logFile = appBase + relativeLog;          // operator +
    IAbsoluteFilePath dataFile = appBase.CombineFile("data/users.json");
    

    Do I/O

    logFile.ParentDirectory.Create();                            // ensure parent exists
    
    using (FileStream stream = logFile.OpenStream(FileMode.Append, FileAccess.Write))
    {
        // write to the file
    }
    
    if (dataFile.Exists)
        Console.WriteLine($"Size: {dataFile.Length} bytes");
    

    Enumerate

    foreach (IAbsoluteFilePath csFile in appBase.GetChildFiles("*.cs", new SearchOptions { Recursive = true }))
        Console.WriteLine(csFile.PathDisplay);
    

    End-to-End Example

    The following example loads a config file relative to the application base, processes it, and writes results to a temp file:

    using Singulink.IO;
    
    // Resolve "config/app.json" relative to the application's base directory.
    IAbsoluteDirectoryPath appBase = DirectoryPath.GetAppBase();
    IAbsoluteFilePath configFile = appBase.CombineFile("config/app.json");
    
    if (configFile.State is not EntryState.Exists)
        throw new FileNotFoundException($"Missing config file: {configFile.PathDisplay}");
    
    // Read the config.
    string json;
    using (StreamReader reader = new(configFile.OpenStream(FileMode.Open, FileAccess.Read, FileShare.Read)))
        json = reader.ReadToEnd();
    
    // Write a result to a uniquely named temp file.
    IAbsoluteFilePath resultFile = FilePath.CreateTempFile();
    
    using (StreamWriter writer = new(resultFile.OpenStream(FileMode.Truncate, FileAccess.Write)))
        writer.Write(Process(json));
    
    Console.WriteLine($"Wrote results to: {resultFile.PathDisplay}");
    
    Tip

    Use PathDisplay for messages, logs and serialization. Use PathExport only when you need a string for an external API. Never use ToString() for I/O; its output is intentionally not a usable path. See Path Formats for the full story.

    Next Steps

    Each subsequent guide takes one slice of the library and covers it in depth:

    • Path Types: the seven path interfaces and what each one offers.
    • Parsing Paths: how to turn strings into paths reliably.
    • PathOptions: controlling what counts as a valid path.
    • Path Formats: Windows, Unix and the cross-platform Universal format.
    • Combining and Navigating Paths, File Names and Extensions, Special Locations.
    • Working with Files, Working with Directories, Searching and Enumeration.
    • Drive and Disk Information, Cached Entry Info, Exception Handling, Interop and Migration.

    If you're coming from System.IO and want a quick sense of what's broken there and why, see Problems with System.IO.

    © Singulink. All rights reserved.