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

Search Results for

    Working with Files

    Overview

    File operations live on IAbsoluteFilePath. Relative file paths can describe a file but cannot perform I/O; combine them with an absolute directory first (see Combining and Navigating Paths).

    Every method described here can throw IOException (or one of its subtypes: FileNotFoundException, DirectoryNotFoundException, UnauthorizedIOAccessException, etc.). See Exception Handling for patterns.

    Existence Checks

    Exists

    Quick boolean:

    if (file.Exists)
        file.Delete();
    

    State

    For richer information, use IAbsolutePath.State. It returns one of four EntryState values:

    Value Meaning
    Exists The file exists.
    ParentExists The file does not exist, but its parent directory does.
    ParentDoesNotExist Neither the file nor its parent directory exist.
    WrongType A different kind of entry (e.g. a directory) exists at this path.
    switch (file.State)
    {
        case EntryState.Exists:             /* open and read */ break;
        case EntryState.ParentExists:       /* prompt user, can create */ break;
        case EntryState.ParentDoesNotExist: /* would need to create the directory tree */ break;
        case EntryState.WrongType:          /* a directory is here: refuse */ break;
    }
    
    Tip

    Use State over Exists when your error handling needs to distinguish between "missing" and "wrong type". WrongType in particular catches a class of bugs that System.IO's boolean checks silently obscure.

    Opening Streams

    OpenStream

    FileStream OpenStream(
        FileMode mode = FileMode.Open,
        FileAccess access = FileAccess.ReadWrite,
        FileShare share = FileShare.None,
        int bufferSize = 4096,
        FileOptions options = FileOptions.None);
    

    Always wrap the returned stream in using:

    using FileStream stream = configFile.OpenStream(FileMode.Open, FileAccess.Read, FileShare.Read);
    using StreamReader reader = new(stream);
    string text = reader.ReadToEnd();
    

    For writes, choose the appropriate FileMode:

    FileMode Behavior
    Open File must exist; throws otherwise.
    OpenOrCreate Open if exists, create if not.
    Create Always create (truncates if exists).
    CreateNew Create; throw if exists.
    Append Open for append (write only); create if missing.
    Truncate Open and truncate; file must exist.

    OpenAsyncStream

    Identical signature to OpenStream but always sets FileOptions.Asynchronous:

    using FileStream stream = file.OpenAsyncStream(FileMode.Create, FileAccess.Write);
    await stream.WriteAsync(buffer);
    
    Note

    The OS may not actually support asynchronous I/O for the underlying handle, in which case the runtime falls back to synchronous internally. The Asynchronous option only opts in to true async when the platform allows it.

    File Properties

    Length and IsReadOnly

    long bytes = file.Length;
    bool readOnly = file.IsReadOnly;
    file.IsReadOnly = true;   // toggle the read-only attribute
    

    Attributes and Timestamps

    Inherited from IAbsolutePath:

    file.Attributes;            // FileAttributes
    file.CreationTime;          // local time
    file.CreationTimeUtc;
    file.LastAccessTime;
    file.LastWriteTime;
    file.LastWriteTimeUtc;
    
    file.Attributes |= FileAttributes.Hidden;
    file.LastWriteTimeUtc = DateTime.UtcNow;
    
    Tip

    Each attribute/timestamp access touches the file system. If you'll read several at once, prefer file.GetInfo() which fetches everything in a single call. See Cached Entry Info.

    Copy, Move, Replace

    CopyTo

    file.CopyTo(destination);                 // throws if destination exists
    file.CopyTo(destination, overwrite: true);
    

    MoveTo

    file.MoveTo(destination);
    file.MoveTo(destination, overwrite: true);
    
    Note

    MoveTo and CopyTo accept any IAbsoluteFilePath as the destination, including across directories or drives. The destination's parent must already exist; call destination.ParentDirectory.Create() first if needed.

    Replace

    Atomically replaces the contents of an existing file with this file, optionally producing a backup of the replaced file:

    newFile.Replace(originalFile, backupFile: null);
    newFile.Replace(originalFile, backupFile: backupPath, ignoreMetadataErrors: true);
    

    Replace is the recommended way to atomically commit changes: write to a temporary file, then call Replace to swap it into place.

    Deleting

    file.Delete();                   // ignores not-found by default
    file.Delete(ignoreNotFound: false); // throws FileNotFoundException if absent
    

    Putting It Together

    Atomic write pattern:

    IAbsoluteFilePath finalPath = appBase.CombineFile("config/app.json");
    IAbsoluteFilePath tempPath = finalPath.AddExtension(".tmp");
    
    finalPath.ParentDirectory.Create();
    
    using (FileStream s = tempPath.OpenStream(FileMode.Create, FileAccess.Write))
    using (StreamWriter w = new(s))
    {
        w.Write(serializedJson);
    }
    
    if (finalPath.Exists)
        tempPath.Replace(finalPath, backupFile: null);
    else
        tempPath.MoveTo(finalPath);
    

    Cached Snapshots

    If you want a single consistent view of a file's metadata (size, attributes, timestamps), call GetInfo() to obtain a CachedFileInfo. See Cached Entry Info.

    Next Steps

    • Working with Directories: many file workflows start by creating a directory.
    • Searching and Enumeration: find the files you want to operate on.
    • Exception Handling: catch I/O errors cleanly.
    © Singulink. All rights reserved.