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, IPath. Members:

    • Name: the final segment (file or directory name).
    • PathDisplay: friendly string suitable for display, logs and round-trippable serialization. Non-empty directory paths always end with the format's separator; file paths never do (see Path Formats).
    • 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, op_Equality and op_Inequality: see Equality below.
    • ToString: diagnostic only; never use this for I/O.

    IAbsolutePath

    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, CreationTimeUtc, LastAccessTime, LastAccessTimeUtc, LastWriteTime, LastWriteTimeUtc.
    • RootDirectory, ParentDirectory (narrowed to IAbsoluteDirectoryPath).
    • GetInfo: returns a CachedEntryInfo.
    • GetLastExistingDirectory: walks up the path until a directory that exists is found.

    IRelativePath

    IRelativePath adds:

    • ToPathFormat: convert a relative path between formats (e.g. Windows to/from Universal).
    • ParentDirectory (narrowed to IRelativeDirectoryPath).

    IFilePath

    IFilePath adds:

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

    See File Names and Extensions.

    IDirectoryPath

    IDirectoryPath adds path-combination members and the + operator:

    • Combine with IRelativeDirectoryPath, IRelativeFilePath or IRelativePath.
    • CombineDirectory, CombineFile.

    See Combining and Navigating Paths.

    IAbsoluteDirectoryPath

    IAbsoluteDirectoryPath combines IAbsolutePath and IDirectoryPath. Adds:

    • IsRoot, IsEmpty.
    • DriveType, FileSystem, AvailableFreeSpace, TotalFreeSpace, TotalSize: see Drive and Disk Information.
    • Create, Delete.
    • MoveTo: move or rename the directory (same volume).
    • GetInfo returning CachedDirectoryInfo.
    • A full set of enumeration methods: see Searching and Enumeration.

    IAbsoluteFilePath

    IAbsoluteFilePath combines IAbsolutePath and IFilePath. Adds:

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

    See Working with Files.

    IRelativeFilePath / IRelativeDirectoryPath

    IRelativeFilePath and 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 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.