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

Search Results for

    Interop and Migration

    This article is a practical guide for code that already uses System.IO, either because you're migrating an existing application or because you depend on a third-party library that takes string, FileInfo or DirectoryInfo parameters. The library is designed to coexist with System.IO so you can adopt it incrementally.

    Bridging at the Boundaries

    The two key bridges are:

    • IAbsolutePath.PathExport: convert a path to a string the underlying file system will reliably accept.
    • SystemExtensions.ToPath: convert FileInfo / DirectoryInfo to a path object.

    Use them at the boundaries of your code where it interacts with non-library APIs. Inside your own code, work with path objects.

    Strings → Paths

    To turn a string you got from somewhere else into a path, parse it with the parser that matches what you know about the input:

    IAbsoluteFilePath path = FilePath.ParseAbsolute(stringFromExternalApi, PathOptions.None);
    

    Use PathOptions.None when the string came from the file system itself (e.g. an OS file picker). The OS may surface "unfriendly" paths that exist and need to be opened. Use PathOptions.NoUnfriendlyNames (the default) for application-defined or user-typed input.

    If the string may not be a valid path at all, the non-throwing FilePath.TryParseAbsolute (or one of the other Try parse methods) reports failure through its return value instead of an exception.

    See Parsing Paths and PathOptions.

    Paths → Strings

    When an external API takes a string path, hand it IAbsolutePath.PathExport (only available on absolute paths):

    ThirdPartyApi.OpenFile(file.PathExport);
    
    Important

    Use IAbsolutePath.PathExport, not IPath.PathDisplay or IPath.ToString, when calling APIs outside this library. PathExport is specially formatted (e.g. with \\?\ on Windows) so the OS won't silently rewrite it.

    FileInfo / DirectoryInfo → Paths

    Use the SystemExtensions extension methods:

    using Singulink.IO;
    
    DirectoryInfo di = new(@"C:\some\path");
    FileInfo fi = new(@"C:\some\file.txt");
    
    IAbsoluteDirectoryPath dirPath = di.ToPath();
    IAbsoluteFilePath filePath = fi.ToPath();
    

    Both extensions parse FileSystemInfo.FullName with PathOptions.NoUnfriendlyNames by default; pass PathOptions.None to accept any path:

    IAbsoluteFilePath filePath = fi.ToPath(PathOptions.None);
    

    When you only have a FileSystemInfo reference (e.g. from a file-picker that surfaces either kind), call SystemExtensions.ToPath on the base type. The returned IAbsolutePath has the runtime type that matches the underlying info object:

    FileSystemInfo fsi = picker.SelectedItem;
    IAbsolutePath path = fsi.ToPath();
    
    switch (path)
    {
        case IAbsoluteFilePath file: /* ... */ break;
        case IAbsoluteDirectoryPath dir: /* ... */ break;
    }
    

    If you also need cached metadata for the entry, use SystemExtensions.ToCachedInfo instead of SystemExtensions.ToPath. It returns a CachedFileInfo / CachedDirectoryInfo for a FileInfo / DirectoryInfo, or the matching concrete type when called on a FileSystemInfo:

    CachedFileInfo cached = fi.ToCachedInfo();
    CachedEntryInfo info = fsi.ToCachedInfo();
    
    Caution

    FileSystemInfo.FullName may have already been rewritten by System.IO (trimming trailing spaces and dots) before SystemExtensions.ToPath sees it. If preserving the exact original characters matters, parse the original string directly with FilePath.ParseAbsolute.

    Paths → FileInfo / DirectoryInfo

    When an external API takes a FileInfo or DirectoryInfo, construct one from IAbsolutePath.PathExport:

    FileInfo fi = new(absoluteFilePath.PathExport);
    DirectoryInfo di = new(absoluteDirectoryPath.PathExport);
    
    ThirdPartyApi.Process(fi);
    

    System.IO → Library Mapping

    A reference of common System.IO operations and their library equivalents:

    Path Construction

    System.IO Library
    Path.Combine IDirectoryPath.CombineFile / IDirectoryPath.CombineDirectory / the + operator
    Path.GetDirectoryName IPath.ParentDirectory
    Path.GetFileName IPath.Name
    Path.GetFileNameWithoutExtension IFilePath.NameWithoutExtension
    Path.GetExtension IFilePath.Extension
    Path.ChangeExtension IFilePath.WithExtension
    Path.GetFullPath FilePath.ParseAbsolute (or FilePath.Parse if it could be relative)
    Path.GetTempPath DirectoryPath.GetTemp
    Path.GetTempFileName FilePath.CreateTempFile

    Files

    System.IO Library
    File.Exists IAbsolutePath.Exists
    File.Open IAbsoluteFilePath.OpenStream
    File.Copy IAbsoluteFilePath.CopyTo
    File.Move IAbsoluteFilePath.MoveTo
    File.Replace IAbsoluteFilePath.Replace
    File.Delete IAbsoluteFilePath.Delete
    File.GetAttributes IAbsolutePath.Attributes
    File.GetLastWriteTimeUtc IAbsolutePath.LastWriteTimeUtc
    A new FileInfo (for metadata) IAbsoluteFilePath.GetInfo (returns CachedFileInfo)

    Directories

    System.IO Library
    Directory.Exists IAbsolutePath.Exists
    Directory.CreateDirectory IAbsoluteDirectoryPath.Create
    Directory.Delete IAbsoluteDirectoryPath.Delete
    Directory.Move IAbsoluteDirectoryPath.MoveTo
    Directory.GetCurrentDirectory DirectoryPath.GetCurrent
    Directory.SetCurrentDirectory DirectoryPath.SetCurrent
    Directory.GetParent IPath.ParentDirectory
    Directory.GetFiles IAbsoluteDirectoryPath.GetChildFiles
    Directory.GetDirectories IAbsoluteDirectoryPath.GetChildDirectories
    Directory.EnumerateFileSystemEntries IAbsoluteDirectoryPath.GetChildEntries

    Drives

    System.IO Library
    DriveInfo.GetDrives DirectoryPath.GetMountingPoints
    DriveInfo.AvailableFreeSpace IAbsoluteDirectoryPath.AvailableFreeSpace (on any absolute directory)
    DriveInfo.TotalFreeSpace IAbsoluteDirectoryPath.TotalFreeSpace
    DriveInfo.TotalSize IAbsoluteDirectoryPath.TotalSize
    DriveInfo.DriveType IAbsoluteDirectoryPath.DriveType
    DriveInfo.DriveFormat IAbsoluteDirectoryPath.FileSystem

    See Drive and Disk Information.

    Migration Strategy

    A pragmatic order of operations:

    1. Adopt at the edges first. New code parses inputs into path objects; old code keeps working with strings until you touch it.
    2. Use SystemExtensions.ToPath to bridge existing FileInfo / DirectoryInfo chains without rewriting the calling code.
    3. Replace try/catch ladders with the parse-vs-IO split. Anything inside a parse step catches ArgumentException; anything inside an I/O step catches IOException. Where a failed parse is routine, the Try parse methods avoid the exception altogether. See Exception Handling.
    4. Convert Directory.GetFiles / Directory.EnumerateFiles calls to GetChild* enumeration with SearchOptions. Pay attention to SearchOptions.MatchCasing: the library's case-insensitive default is consistent across platforms, which is a behavior change from System.IO on Unix.
    5. Drop DriveInfo workarounds. UNC paths, mounted subdirectories and per-user quotas are all handled by the disk-space members on absolute directories.

    When You Still Need Strings

    You'll still encounter APIs that demand a string. Continue using IAbsolutePath.PathExport:

    public void Extract(IAbsoluteFilePath archive, IAbsoluteDirectoryPath targetDir)
    {
        ZipFile.ExtractToDirectory(archive.PathExport, targetDir.PathExport);
    }
    

    Don't use IPath.PathDisplay for I/O even if it looks the same as PathExport for typical paths; the difference is invisible until something subtle goes wrong.

    Next Steps

    Two guides go deeper on the ideas used here:

    • Path Formats: the difference between IPath.PathDisplay, IAbsolutePath.PathExport and IPath.ToString.
    • Exception Handling: replace System.IO catch ladders with the cleaner two-phase model.
    © Singulink. All rights reserved.