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

Search Results for

    Path Types

    Overview

    Every path in Singulink.IO.FileSystem is represented by an interface. The interface tells you, statically, two independent facts about the path:

    1. Is it absolute or relative?
    2. Does it point to a file or a directory?

    The combination produces four concrete interfaces (one of which every path object implements) plus three abstractions you can use when only one of the two facts matters.

    The Interface Hierarchy

    The hierarchy splits along two independent axes and combines into four leaf interfaces. Each leaf is the type used in practice; the others exist so your APIs can ask for exactly as much as they need.

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

    The two axes:

    • Absolute vs relative: exposed by IAbsolutePath and IRelativePath. Both extend IPath.
    • File vs directory: exposed by IFilePath and IDirectoryPath. Both extend IPath.

    Every concrete path implements one of the four leaves and inherits members from both axes. Use the most specific interface you can in your APIs; it's how the type system catches mistakes for you.

    Members by Interface

    IPath

    The common base of every path. Members:

    • Name: the final segment (file or directory name).
    • PathDisplay: friendly string suitable for display, logs and round-trippable serialization.
    • PathFormat: the PathFormat of the path (Windows, Unix or Universal).
    • HasParentDirectory, ParentDirectory: walk upward.
    • IsRooted: true for absolute paths and Windows rooted-relative paths (e.g. \Some\Path).
    • Equals / == / !=: see Equality below.
    • ToString(): diagnostic only; never use this for I/O.

    IAbsolutePath

    Adds members that only make sense for fully-qualified paths:

    • PathExport: the only string form safe to hand to non-library APIs.
    • IsUnc: true for UNC paths (Windows only).
    • Exists: convenience boolean.
    • State: richer status, returns one of the EntryState values: Exists, ParentExists, ParentDoesNotExist or WrongType.
    • Attributes (get/set), CreationTime[Utc], LastAccessTime[Utc], LastWriteTime[Utc].
    • RootDirectory, ParentDirectory (narrowed to IAbsoluteDirectoryPath).
    • GetInfo(): returns a CachedEntryInfo.
    • GetLastExistingDirectory(): walks up the path until a directory that exists is found.

    IRelativePath

    Adds:

    • ToPathFormat(format, options): convert a relative path between formats (e.g. Windows ↔ Universal).
    • ParentDirectory (narrowed to IRelativeDirectoryPath).

    IFilePath

    Adds:

    • NameWithoutExtension, Extension.
    • WithExtension(ext, options): replace the trailing extension.
    • AddExtension(ext, options): append an extension, preserving any existing one.

    See File Names and Extensions.

    IDirectoryPath

    Adds path-combination members and the + operator:

    • Combine(IRelativeDirectoryPath / IRelativeFilePath / IRelativePath).
    • CombineDirectory(span, [format,] options), CombineFile(span, [format,] options).

    See Combining and Navigating Paths.

    IAbsoluteDirectoryPath

    Combines IAbsolutePath and IDirectoryPath. Adds:

    • IsRoot, IsEmpty.
    • DriveType, FileSystem, AvailableFreeSpace, TotalFreeSpace, TotalSize: see Drive and Disk Information.
    • Create(), Delete(recursive, ignoreNotFound).
    • GetInfo() returning CachedDirectoryInfo.
    • A full set of enumeration methods: see Searching and Enumeration.

    IAbsoluteFilePath

    Combines IAbsolutePath and IFilePath. Adds:

    • IsReadOnly, Length.
    • OpenStream(...), OpenAsyncStream(...).
    • CopyTo, MoveTo, Replace, Delete.
    • GetInfo() returning CachedFileInfo.

    See Working with Files.

    IRelativeFilePath / IRelativeDirectoryPath

    Combine IRelativePath with IFilePath / IDirectoryPath. Their members are the union of the two parents, narrowed to relative return types.

    Why Strong Typing

    Static typing catches at compile time the bugs you'd otherwise hit at runtime. A few examples:

    void OpenLog(IAbsoluteFilePath path);
    
    OpenLog(someDirectoryPath);          // compile error: directory is not a file
    OpenLog(someRelativeFilePath);       // compile error: relative is not absolute
    

    The library applies the same discipline internally: file system operations only exist on absolute paths, so a relative path can never accidentally be opened against the current working directory.

    Pattern Matching

    When you don't know statically which kind of path you have (e.g. you used FilePath.Parse which returns IFilePath), use pattern matching:

    IFilePath file = FilePath.Parse(userInput);
    
    if (file is IAbsoluteFilePath absolute)
    {
        using FileStream s = absolute.OpenStream();
        // ...
    }
    else
    {
        IRelativeFilePath relative = (IRelativeFilePath)file;
        IAbsoluteFilePath resolved = DirectoryPath.GetCurrent() + relative;
        // ...
    }
    
    Tip

    If you know up front that a string must be absolute (or must be relative), call ParseAbsolute or ParseRelative directly. The return type is the specific interface, so no cast or pattern match is needed.

    Equality

    Two paths are equal when:

    • They implement the same concrete type (e.g. both are IAbsoluteFilePath).
    • Their PathFormat is the same.
    • Their root segments compare equal case-insensitively (drive letter or UNC name).
    • The remainder of the path compares equal case-sensitively.
    var a = FilePath.ParseAbsolute(@"C:\Apps\MyApp\config.json");
    var b = FilePath.ParseAbsolute(@"c:\Apps\MyApp\config.json");
    var c = FilePath.ParseAbsolute(@"C:\apps\MyApp\config.json");
    
    a == b;   // true : root casing differs, but the root is case-insensitive
    a == c;   // false: non-root segments are case-sensitive
    
    Note

    Equality is textual. Two different paths that resolve to the same physical entry through symbolic links or case-insensitive file systems are not equal; equality reflects the path, not what it points to.

    Next Steps

    • Parsing Paths: turn strings into instances of these interfaces.
    • Path Formats: understand the third dimension (PathFormat) that affects every path.
    • Combining and Navigating Paths: build new paths from existing ones.
    © Singulink. All rights reserved.