I am a beginner zig programmer coming from Rust & Golang. I've been searching online for a couple hours now and have only managed to find absurdly complex and inefficient solutions that do not fit my problem.
//Import standard library
const std = @import("std");
pub fn main() !void {
//Create an allocator
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
//Open desired file
var file = try std.fs.cwd().openFile("./state-of-union.txt", .{});
defer file.close();
//Regular buffer for demonstration purposes
var b = std.mem.zeroes([100]u8);
const x = try file.readAll(&b);
std.debug.print("Test bytes read: {any}\n", .{x});
//My *ACTUAL* buffer where the error arises
var buffer = std.ArrayList(u8).init(gpa.allocator());
defer buffer.deinit();
const temp = try file.readAll(buffer.items);
//Added to show that my code is not reading into my heap allocated array
std.debug.print("Actual bytes read: {any}\n", .{temp});
//Print file contents as string
std.debug.print("{s}\n", .{buffer.items});
}
Output:
~\Desktop\ztest via ↯ v0.12.0-dev.3152+90c1a2c41
❯ zig build run
Test bytes read: 100
Actual bytes read: 0
Now, if I attempt to change buffer.items to &buffer.items like I did with the stack allocated buffer, I get a compile time error:
~\Desktop\ztest via ↯ v0.12.0-dev.3152+90c1a2c41
❯ zig build run
run
└─ run ztest
└─ zig build-exe ztest Debug native 1 errors
src\main.zig:21:35: error: expected type '[]u8', found '*[]u8'
const temp = try file.readAll(&buffer.items);
^~~~~~~~~~~~~
C:\Program Files\zig\lib\std\fs\File.zig:1049:36: note: parameter type declared here
pub fn readAll(self: File, buffer: []u8) ReadError!usize {
^~~~
referenced by:
callMain: C:\Program Files\zig\lib\std\start.zig:511:32
WinStartup: C:\Program Files\zig\lib\std\start.zig:350:45
remaining reference traces hidden; use '-freference-trace' to see all reference traces
error: the following command failed with 1 compilation errors:
C:\Program Files\zig\zig.exe build-exe -ODebug -Mroot=C:\Users\user\Desktop\ztest\src\main.zig --cache-dir C:\Users\user\Desktop\ztest\zig-cache --global-cache-dir C:\Users\user\AppData\Lo
cal\zig --name ztest --listen=-
Build Summary: 2/7 steps succeeded; 1 failed (disable with --summary none)
run transitive failure
└─ run ztest transitive failure
├─ zig build-exe ztest Debug native 1 errors
└─ install transitive failure
└─ install ztest transitive failure
└─ zig build-exe ztest Debug native (reused)
error: the following build command failed with exit code 1:
C:\Users\user\Desktop\ztest\zig-cache\o\b91671406079ab60e0e46cf8f3eb5e2c\build.exe C:\Program Files\zig\zig.exe C:\Users\user\Desktop\ztest C:\Users\logan\Desktop\ztest\zig-cache C:\Users\user\AppData\Local\zig --seed 0xdd4267fc -Z3028407686deb58d run
The main function opens the desired file, then (after demonstration) declares a heap allocated buffer and attempts to read from the file and to the buffer. Then print the buffer contents.
Any help is appreciated, I truly have no clue what is wrong. (Also if anybody can link me to some official zig examples that would be truly incredible. I am having a hard time finding them.)
File.readAll
tries to fill the provided slice up to its .len
. But since you pass it the underlying slice of a freshly initialized and empty ArrayList
, no memory has been allocated yet and the slice has .len
equal to 0.
Instead of creating an empty ArrayList
, you could create one with capacity 100 by using std.ArrayList(u8).initCapacity(gpa.allocator(), 100)
instead of .init(gpa.allocator())
. Then I think you also need to call buffer.expandToCapacity()
to set the underlying buffer.items.len
to 100 as well, which will then be picked up by file.readAll
.
Or, simpler, keep your original code using init
, but add buffer.resize(100)
before file.readAll(buffer.items)
.
(The ArrayList
documentation seems to be broken/nonexistent at the moment, so you have to figure this out by reading the source code: ziglang.org/GitHub.)
In addition, readAll
won't read any more bytes if the end of the file has been reached, so if you call it twice in your example code and the file is smaller than 200 bytes, you have to keep that in mind.