Part 19: Files

Everything so far has lived in memory and vanished when the program ended. A file is how data outlives the program — and it is also where a program meets a world it does not control: names that are not valid text, disks that fill up, files that someone else deletes or reads half-written. This part tours the Path package, which names files, and the FileSystem package, which reads, writes and manages them, and it handles every failure along the way.

What you will learn

  • Why a path is not a string, and how OsString, Path and PathBuffer take one apart, build one and tidy one.
  • Opening, writing, reading and closing a file, with IoError handled at every step — including the end of the file, which arrives as a failure.
  • Making, listing and removing directories, and asking the filesystem what a name refers to.
  • Writing fixed-width binary records, and refusing one that the file cut short.
  • Gathering small writes in a buffer, and knowing when the bytes really reach the file.
  • Replacing a file so that no reader ever sees it half-written, and scratch files that clean up after themselves.

A file's life

Every lesson here covers a piece of one sequence: turn text into a path, open the file, move bytes, close it — and check each step, because each one asks the operating system for something it may refuse.

sequenceDiagram
    participant P as Program
    participant F as File
    participant OS as Operating system
    Note over P: OsString::FromText(text)?<br/>Path::FromView(…)
    P->>F: File::Open(path, Writing())?
    F->>OS: create the file, or empty it
    P->>F: WriteAll(file, bytes)?
    F->>OS: Write, again and again until every byte is out
    P->>F: Close()?
    OS-->>P: success, or a failure delayed until now
    P->>F: File::Open(path, Reading())?
    loop until the end of the file
        P->>F: Read(buffer[..])
        F-->>P: a count of bytes, or an IoError
    end
    Note over P: IsEnd() is true: the file is read
    P->>F: Close()?
    P->>OS: DeleteFile(path)?
You want to…UseLesson
take a path apartComponents, FileName, ParentPath
build a path from piecesJoin, PathBuffer::PushPath join
compare or display pathsNormalizePath normalize
read or write a text fileFile::Open, WriteAll, ReadFile
list a directoryReadDirectory, NextDirectory
ask whether a file exists, and what it isMetadataOfMetadata
store numbers as bytesWriteUint32, ReadUint32, …Binary
make many small writes cheaplyBufferedWriterBuffered I/O
replace a file without a half-written momentWriteAtomically, AtomicWriteAtomic file
scratch space that removes itselfTemporaryFileTemporary file

Lessons

LessonWhat you will learn
19.1Pathsplit a path into its parts, and see why a path is not a string
19.2Path joinbuild a path from parts
19.3Path normalizetidy a path by removing . and ..
19.4Filewrite text to a file and read it back, handling failure at every step
19.5Directorycreate, list, and remove directories
19.6Metadataask a file for its size and kind
19.7Binaryread and write fixed-width values and raw bytes
19.8Buffered I/Obuffer writes and flush them
19.9Atomic filereplace a file's contents all at once or not at all
19.10Temporary filea scratch file that cleans up after itself

Before you start

This part leans hard on Part 9: Errors — every lesson's Main is a fallible main with an error sum on its failure side, and the lessons use Catch, Guard, Nested fallible and Coalesce exit. It also uses Move and Destructor from Part 11, Interface value and Iterator from Part 12, Allocator from Part 15 and Endian from Part 16. Each lesson's package is in the Examples repository's Files/ folder:

cd Examples/Files/File
rux run

The programs create their files inside their own package's Bin/ folder and delete them before they finish. If a run stops part-way, a leftover file or Bin/scratch directory may need deleting by hand.

After this part

Part 20: Utilities covers time, randomness, hashing and UUIDs — including the Timestamp that Metadata reported. Part 21: Data formats then gives your files a structure, and its checkpoint project, Notes, keeps a to-do list as JSON in a file — saved with WriteAtomically, loaded back, and recovered when the file is missing or damaged.

The Rux Reference describes the language features these packages are built from: Interfaces, the mechanism behind Reader and Writer, and Enumerations, the shape of IoErrorKind and FileKind.