Skip to content

Stream read file in Zig

Published:

Stream a file into an ArrayList

Coming from a language like Go you might be spoiled by its Reader interfaces. The reader/writer concept does exist in Zig but is obviously in its pre 1.0.0 release state. This was tested with 0.14.0-dev.1702+26d35cc11. The below shows how to read a file in zig in a performant mannor. Using an ArrayList and also a fixed size buffer.

Buffered reader with ArrayList backing

const std = @import("std");
const print = std.debug.print;

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const file = try std.fs.cwd().openFile("loadtest.js", .{});
    defer file.close();

    var buf_reader = std.io.bufferedReader(file.reader());
    const reader = buf_reader.reader();

    var line = std.ArrayList(u8).init(allocator);
    defer line.deinit();

    const writer = line.writer();
    while (true) {
        defer line.clearRetainingCapacity();
        reader.streamUntilDelimiter(writer, '\n', null) catch |err| {
            switch (err) {
                error.EndOfStream => {
                    return;
                },
                else => {
                    std.debug.print("error: {any}", .{err});
                    return;
                },
            }
        };
        print("{s}\n", .{line.items});
    }
}
./readfile_streaming_arraylist_alloc  2.61s user 0.28s system 99% cpu 2.891 total

Buffered reader with a fixed size [512]u8 buffer

const std = @import("std");
const print = std.debug.print;
pub fn main() !void {
    const file = try std.fs.cwd().openFile("loadtest.js", .{});
    defer file.close();

    var buf_reader = std.io.bufferedReader(file.reader());
    const reader = buf_reader.reader();

    var line: [512]u8 = undefined; // make sure your line len is less than 512
    var writer = std.io.fixedBufferStream(&line);

    while (true) {
        defer writer.reset();
        reader.streamUntilDelimiter(writer.writer(), '\n', null) catch |err| {
            switch (err) {
                error.EndOfStream => {
                    return;
                },
                else => {
                    std.debug.print("{any}", .{err});
                },
            }
        };

        print("{s}\n", .{line[0..writer.pos]});
    }
}

./readfile_streaming_buf  2.03s user 0.28s system 99% cpu 2.325 total

Conclusion

As you can see there is a slight gain in performance with using a fixed size buffer. The file i used to test was 1.1gb in size.


Previous Post
HTTP Server in Zig
Next Post
Adding Dependencies from GitHub in Zig