257 lines
7.3 KiB
Markdown
257 lines
7.3 KiB
Markdown
# File System API Reference (Zig 0.16.0)
|
|
|
|
Primary release-note source: https://ziglang.org/download/0.16.0/release-notes.html
|
|
|
|
Zig 0.16 migrates file-system operations to `std.Io`. Use `std.Io.Dir`, `std.Io.File`, and an explicit `std.Io` parameter. `std.fs` is now mostly path helpers and deprecated compatibility names.
|
|
|
|
The snippets below are focused fragments. They assume `const std =
|
|
@import("std")`, a caller-supplied `io: std.Io`, a suitable allocator, and any
|
|
named application values such as `max_size`, `from`, and `to`.
|
|
|
|
## Core Types
|
|
|
|
```zig
|
|
std.Io.Dir // Directory handle and file-system operations
|
|
std.Io.File // File handle, readers, writers, stat, locking
|
|
std.Io.File.Atomic
|
|
std.Io.File.MemoryMap
|
|
std.Io.Dir.path // Path helpers; std.fs.path is deprecated compatibility
|
|
```
|
|
|
|
## Current Directory
|
|
|
|
```zig
|
|
const cwd = std.Io.Dir.cwd();
|
|
```
|
|
|
|
Do not use old `std.fs.cwd()` in new 0.16 code.
|
|
|
|
## Opening Files
|
|
|
|
```zig
|
|
const file = try std.Io.Dir.cwd().openFile(io, "data.txt", .{});
|
|
defer file.close(io);
|
|
|
|
const rw = try std.Io.Dir.cwd().openFile(io, "data.txt", .{
|
|
.mode = .read_write,
|
|
});
|
|
defer rw.close(io);
|
|
```
|
|
|
|
## Creating Files
|
|
|
|
```zig
|
|
const file = try std.Io.Dir.cwd().createFile(io, "out.txt", .{});
|
|
defer file.close(io);
|
|
```
|
|
|
|
With default options, `createFile` truncates an existing regular file. Use the
|
|
exclusive-create option when overwriting must fail. Other options cover read
|
|
access, `permissions`, and locking where supported. File access mode is an
|
|
`openFile` option, not the name of the creation-permissions field.
|
|
|
|
## Reading Files
|
|
|
|
### Stream With Reader
|
|
|
|
```zig
|
|
const file = try std.Io.Dir.cwd().openFile(io, "data.txt", .{});
|
|
defer file.close(io);
|
|
|
|
var buffer: [4096]u8 = undefined;
|
|
var file_reader = file.reader(io, &buffer);
|
|
const reader = &file_reader.interface;
|
|
|
|
while (try reader.takeDelimiter('\n')) |line| {
|
|
_ = line;
|
|
}
|
|
```
|
|
|
|
### Allocate Whole File
|
|
|
|
```zig
|
|
const bytes = try std.Io.Dir.cwd().readFileAlloc(io, "data.txt", allocator, .limited(1024 * 1024));
|
|
defer allocator.free(bytes);
|
|
```
|
|
|
|
The limit uses `std.Io.Limit`. Hitting the limit returns `error.StreamTooLong`.
|
|
`readFileAlloc` creates a file reader internally and reads until the supplied
|
|
limit. Use an explicit `File.Reader` when streaming, reusing buffers, or
|
|
controlling incremental consumption.
|
|
|
|
### Read To End From Existing File
|
|
|
|
```zig
|
|
var buffer: [4096]u8 = undefined;
|
|
var file_reader = file.reader(io, &buffer);
|
|
const bytes = try file_reader.interface.allocRemaining(allocator, .limited(max_size));
|
|
defer allocator.free(bytes);
|
|
```
|
|
|
|
## Writing Files
|
|
|
|
### Stream With Writer
|
|
|
|
```zig
|
|
const file = try std.Io.Dir.cwd().createFile(io, "out.txt", .{});
|
|
defer file.close(io);
|
|
|
|
var buffer: [4096]u8 = undefined;
|
|
var file_writer = file.writer(io, &buffer);
|
|
const writer = &file_writer.interface;
|
|
|
|
try writer.print("value={d}\n", .{42});
|
|
try writer.writeAll("raw bytes\n");
|
|
try writer.flush();
|
|
```
|
|
|
|
### Write Whole File
|
|
|
|
```zig
|
|
try std.Io.Dir.cwd().writeFile(io, .{
|
|
.sub_path = "out.txt",
|
|
.data = "hello\n",
|
|
});
|
|
```
|
|
|
|
## Standard I/O
|
|
|
|
```zig
|
|
var stdout_buffer: [4096]u8 = undefined;
|
|
var stdout_writer = std.Io.File.stdout().writer(io, &stdout_buffer);
|
|
try stdout_writer.interface.print("hello\n", .{});
|
|
try stdout_writer.interface.flush();
|
|
|
|
var stderr_buffer: [4096]u8 = undefined;
|
|
var stderr_writer = std.Io.File.stderr().writer(io, &stderr_buffer);
|
|
try stderr_writer.interface.print("error: {s}\n", .{"message"});
|
|
try stderr_writer.interface.flush();
|
|
```
|
|
|
|
```zig
|
|
var stdin_buffer: [4096]u8 = undefined;
|
|
var stdin_reader = std.Io.File.stdin().reader(io, &stdin_buffer);
|
|
|
|
if (try stdin_reader.interface.takeDelimiter('\n')) |line| {
|
|
_ = line;
|
|
}
|
|
```
|
|
|
|
## Directories
|
|
|
|
```zig
|
|
var dir = try std.Io.Dir.cwd().openDir(io, "assets", .{ .iterate = true });
|
|
defer dir.close(io);
|
|
|
|
try std.Io.Dir.cwd().createDir(io, "new-dir", .default_dir);
|
|
try std.Io.Dir.cwd().createDirPath(io, "path/to/nested");
|
|
```
|
|
|
|
Both walking APIs require a directory opened with `.iterate = true`; iterating
|
|
without that capability is illegal behavior. Use other `openDir` options for
|
|
access/no-follow behavior as needed.
|
|
|
|
## Walking
|
|
|
|
Use `walk` for full recursive walks and `walkSelectively` when you want to decide which directories to enter.
|
|
|
|
```zig
|
|
var walker = try dir.walk(allocator);
|
|
defer walker.deinit();
|
|
|
|
while (try walker.next(io)) |entry| {
|
|
_ = entry;
|
|
}
|
|
```
|
|
|
|
```zig
|
|
var walker = try dir.walkSelectively(allocator);
|
|
defer walker.deinit();
|
|
|
|
while (try walker.next(io)) |entry| {
|
|
if (entry.kind == .directory and shouldEnter(entry)) {
|
|
try walker.enter(io, entry);
|
|
}
|
|
}
|
|
```
|
|
|
|
## Metadata
|
|
|
|
```zig
|
|
const stat = try file.stat(io);
|
|
|
|
const size = stat.size;
|
|
const kind = stat.kind;
|
|
const modified = stat.mtime;
|
|
const accessed = stat.atime orelse return error.FileAccessTimeUnavailable;
|
|
_ = .{ size, kind, modified, accessed };
|
|
```
|
|
|
|
`atime` is optional in 0.16.
|
|
|
|
Setting timestamps uses structured options:
|
|
|
|
```zig
|
|
try file.setTimestamps(io, .{
|
|
.access_timestamp = .init(stat.atime),
|
|
.modify_timestamp = .init(stat.mtime),
|
|
});
|
|
```
|
|
|
|
## Paths
|
|
|
|
`std.Io.Dir.path` / `std.fs.path` functions handle Windows paths more consistently in 0.16.
|
|
|
|
The relative-path helpers are pure and receive the current directory rather
|
|
than querying the OS. `relative` and `relativeWindows` also accept an optional
|
|
environment map for Windows per-drive current-directory resolution;
|
|
`relativePosix` has a distinct signature without that map.
|
|
|
|
```zig
|
|
const cwd_path = try std.process.currentPathAlloc(io, allocator);
|
|
defer allocator.free(cwd_path);
|
|
|
|
const rel = try std.fs.path.relative(allocator, cwd_path, environ_map, from, to);
|
|
defer allocator.free(rel);
|
|
```
|
|
|
|
## Atomic Files
|
|
|
|
Obtain a `std.Io.File.Atomic` value through `Dir.createFileAtomic`, then use its
|
|
public cleanup/materialization lifecycle. Do not construct `File.Atomic`
|
|
directly or hand-roll random temporary names; the helper routes entropy and
|
|
filesystem work through `std.Io`.
|
|
|
|
## Absolute Operations
|
|
|
|
Many old `std.fs.*Absolute` functions moved to `std.Io.Dir.*Absolute`, for example:
|
|
|
|
- `std.fs.openFileAbsolute` -> `std.Io.Dir.openFileAbsolute`
|
|
- `std.fs.createFileAbsolute` -> `std.Io.Dir.createFileAbsolute`
|
|
- `std.fs.deleteFileAbsolute` -> `std.Io.Dir.deleteFileAbsolute`
|
|
- `std.fs.renameAbsolute` -> `std.Io.Dir.renameAbsolute`
|
|
- `std.fs.accessAbsolute` -> `std.Io.Dir.accessAbsolute`
|
|
|
|
Many `Z` and `W` path-specific helpers were removed.
|
|
|
|
## Migration Map
|
|
|
|
| Old 0.15-style API | Zig 0.16 API |
|
|
|--------------------|--------------|
|
|
| `std.fs.cwd()` | `std.Io.Dir.cwd()` |
|
|
| `std.fs.File.stdout()` | `std.Io.File.stdout()` |
|
|
| `file.close()` | `file.close(io)` |
|
|
| `dir.close()` | `dir.close(io)` |
|
|
| `file.reader(&buf)` | `file.reader(io, &buf)` |
|
|
| `file.writer(&buf)` | `file.writer(io, &buf)` |
|
|
| `dir.readFileAlloc(allocator, path, max)` | `dir.readFileAlloc(io, path, allocator, .limited(max))` |
|
|
| `file.readToEndAlloc(allocator, max)` | `file.reader(io, &buf).interface.allocRemaining(allocator, .limited(max))` |
|
|
| `std.process.getCwdAlloc(allocator)` | `std.process.currentPathAlloc(io, allocator)` |
|
|
|
|
## Application Guidance
|
|
|
|
- Prefer an application's virtual or asset file-system abstraction for runtime reads when one exists.
|
|
- New direct file operations still need an `io` parameter at the API boundary.
|
|
- Writes should be explicit and use `std.Io.Dir` / `std.Io.File` until a project abstraction owns write policy.
|
|
- Avoid local fallback `Io.Threaded` construction in low-level file helpers; pass or store `io`.
|