Skip to main content
Version: Zig 0.15.2

Readers and Writers

std.io.Writer and std.io.Reader provide standard ways of making use of IO. std.ArrayList(u8) has a writer method which gives us a writer. Let's use it.

const std = @import("std");
const expect = std.testing.expect;
const eql = std.mem.eql;
const ArrayList = std.ArrayList;
const allocator = std.testing.allocator;

test "io writer usage" {
var list: ArrayList(u8) = .empty;
defer list.deinit(allocator);

try list.print(allocator, "Hello {s}!", .{"World"});

try expect(eql(u8, list.items, "Hello World!"));
}

Here we will use a reader to copy the file's contents into an allocated buffer. The second argument of readAllAlloc is the maximum size that it may allocate; if the file is larger than this, it will return error.StreamTooLong.

const std = @import("std");
const expect = std.testing.expect;
const eql = std.mem.eql;
const test_allocator = std.testing.allocator;
test "io reader usage" {
const message = "Hello File!";

const file = try std.fs.cwd().createFile(
"junk_file2.txt",
.{ .read = true },
);
defer file.close();

try file.writeAll(message);
try file.seekTo(0);

var file_buffer: [1024]u8 = undefined;
var file_reader = file.reader(&file_buffer);

const contents = try file_reader.interface.readAlloc(
test_allocator,
message.len,
);
defer test_allocator.free(contents);

try expect(eql(u8, contents, message));
}

A common usecase for readers is to read until the next line (e.g. for user input). Here we will do this with the std.fs.File.stdin() file.

const std = @import("std");
const expect = std.testing.expect;
const eql = std.mem.eql;
test "read until next line" {
var stdout_buf: [1024]u8 = undefined;
var stdout_writer = std.fs.File.stdout().writer(&stdout_buf);
const stdout: *std.io.Writer = &stdout_writer.interface;

var stdin_buf: [1024]u8 = undefined;
var stdin_reader = std.fs.File.stdin().reader(&stdin_buf);
const stdin: *std.io.Reader = &stdin_reader.interface;

try stdout.writeAll("Enter your name\n");
try stdout.flush();

const bare_line = try stdin.takeDelimiter('\n') orelse unreachable;
const line = std.mem.trim(u8, bare_line, "\r");

try stdout.print("Your name is: \"{s}\"\n", .{line});
try stdout.flush();
}