Reputation: 9543
How can I read a file in zig, and run over it line by line?
I did found os.File.openRead
, but it seems old cause it says that container 'std.os' has no member called 'File'
.
Upvotes: 20
Views: 37693
Reputation: 8656
EDIT: This method may no longer be valid as written in Zig 0.11.0 onwards, I'll leave the original content below and update the answer at some point:
I muddled through this by looking at the Zig library source/docs, so this might not be the most idiomatic way:
const std = @import("std");
pub fn main() anyerror!void {
// Get an allocator
var gp = std.heap.GeneralPurposeAllocator(.{ .safety = true }){};
defer _ = gp.deinit();
const allocator = &gp.allocator;
// Get the path
var path_buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
const path = try std.fs.realpath("./src/main.zig", &path_buffer);
// Open the file
const file = try std.fs.openFileAbsolute(path, .{ .read = true });
defer file.close();
// Read the contents
const buffer_size = 2000;
const file_buffer = try file.readToEndAlloc(allocator, buffer_size);
defer allocator.free(file_buffer);
// Split by "\n" and iterate through the resulting slices of "const []u8"
var iter = std.mem.split(file_buffer, "\n");
var count: usize = 0;
while (iter.next()) |line| : (count += 1) {
std.log.info("{d:>2}: {s}", .{ count, line });
}
}
The above is a little demo program that you should be able to drop into the default project created from zig init-exe
, it'll just print out it's own contents, with a line number.
You can also do this without allocators, provided you supply the required buffers.
I'd also recommend checking out this great resource: https://ziglearn.org/chapter-2/#readers-and-writers
Note: I'm currently running a development version of Zig from master (reporting 0.9.0), but I think this has been working for the last few official releases.
Upvotes: 8
Reputation: 65
This is the best way I have found to read in a file in Zig. Short, clean, and functional.
@embedFile returns a compile time constant pointer to null-terminated, fixed-size array with length equal to the byte count of the file given by path. The contents of the array are the contents of the file. This is equivalent to a string literal with the file contents.
const std = @import("std");
const data = @embedFile("calories.txt");
const split = std.mem.split;
pub fn main() !void {
var splits = split(u8, data, "\n");
while (splits.next()) |line| {
std.debug.print("{s}\n", .{line});
}
}
Upvotes: 4
Reputation: 1496
Below is a test case that shows how to create a file, write to it then open the same file and read its content.
const std = @import("std");
const testing = std.testing;
const expect = testing.expect;
test "create a file and then open and read it" {
var tmp_dir = testing.tmpDir(.{}); // This creates a directory under ./zig-cache/tmp/{hash}/test_file
// defer tmp_dir.cleanup(); // commented out this line so, you can see the file after execution finished.
var file1 = try tmp_dir.dir.createFile("test_file", .{ .read = true });
defer file1.close();
const write_buf: []const u8 = "Hello Zig!";
try file1.writeAll(write_buf);
var file2 = try tmp_dir.dir.openFile("test_file", .{});
defer file2.close();
const read_buf = try file2.readToEndAlloc(testing.allocator, 1024);
defer testing.allocator.free(read_buf);
try testing.expect(std.mem.eql(u8, write_buf, read_buf));
}
Check out fs
package tests on Github or on your local machine under <zig-install-dir>/lib/fs/test.zig
.
Also note that test allocator only works for tests. In your actual source code you need to choose an appropriate allocator.
Upvotes: 1
Reputation: 6740
std.io.reader.readUntilDelimiterOrEof
lets your read any std.io.reader
line by line. You usually get the reader of something like a file by calling it’s reader()
method. So for example:
var file = try std.fs.cwd().openFile("foo.txt", .{});
defer file.close();
var buf_reader = std.io.bufferedReader(file.reader());
var in_stream = buf_reader.reader();
var buf: [1024]u8 = undefined;
while (try in_stream.readUntilDelimiterOrEof(&buf, '\n')) |line| {
// do something with line...
}
The std.io.bufferedReader
isn’t mandatory but recommended for better performance.
Upvotes: 32
Reputation: 1914
To open a file and get a file descriptor back
std.os.open
https://ziglang.org/documentation/0.6.0/std/#std;os.open
To read from the file
std.os.read
https://ziglang.org/documentation/0.6.0/std/#std;os.read
I can't find a .readlines() style function in the zig standard library. You'll have to write your own loop to find the \n
characters.
Upvotes: 2