3

I would like to avoid making a set size buffer because of things like a file being too big, or small enough that there is empty space in the buffer. An ArenaAllocator sounds promising since you can allocate more space as needed. Is there a "proper" way to do this, i.e. load a .json file passed as a command line argument into a buffer?

steamsy
  • 104
  • 1
  • 8

4 Answers4

2

How can you create a buffer of the same size as a file?

You can request file's size and allocate the same amount of memory:

var file = try std.fs.cwd().openFile("file.txt", .{ open = true }));

const file_size = (try file.stat()).size;
var buffer = try allocator.alloc(u8, file_size);

Then you can read the file by using readNoEof:

try file.reader().readNoEof(buffer);

Alternatively, you can use File's readToEndAlloc function:

const size_limit = std.math.maxInt(u32); // or any other suitable limit
var result = try file.readToEndAlloc(allocator, size_limit);
sigod
  • 3,514
  • 2
  • 21
  • 44
  • On master 0.9.0 I had to replace `.{ open = true }` with `std.fs.O_RDONLY` but this probably works for stable – steamsy Dec 03 '21 at 04:39
  • 1
    If the file is available at compile time, you could use the `@embedFIle` function: https://ziglang.org/documentation/master/#embedFile – Dave Mason Feb 19 '22 at 15:56
1

using GeneralPurposeAllocator. you can learn more about allocators in https://youtu.be/vHWiDx_l4V0

const std = @import("std");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = &gpa.allocator;
    const args = try std.process.argsAlloc(allocator);
    defer std.process.argsFree(allocator, args);
    const file = try std.fs.cwd().openFile(args[1], .{});
    const file_content = try file.readToEndAlloc(allocator, 1024 * 1024); // 1MB max read size
    defer allocator.free(file_content);
    std.debug.print("{s}", .{file_content});
}
Ali Chraghi
  • 613
  • 6
  • 16
1

On 0.10.0-dev.2345+9747303d1, here's what worked for me:

const std = @import("std");

pub fn main() !void {
    var file = try std.fs.cwd().openFile("test.ts", .{ .mode = .read_only });
    const file_size = (try file.stat()).size;
    const allocator = std.heap.page_allocator;
    var buffer = try allocator.alloc(u8, file_size);
    try file.reader().readNoEof(buffer);

    std.debug.print("{s}\n", .{buffer});
}

OpenFlags for .openFile is defined here: https://github.com/ziglang/zig/blob/master/lib/std/fs/file.zig#L80

Lawrence Chen
  • 11
  • 1
  • 1
1

None of the answers worked for me in Zig today sine a few interfaces changed (e.g. allocator -> allocator()). Here is what worked for me (Dec 2022):

const std = @import("std");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = &gpa.allocator();
    var file = try std.fs.cwd().openFile("./sample.txt", .{});
    const file_content = try file.readToEndAlloc(allocator.*, 10 * 1024 * 1024); // 10MB read
    defer allocator.free(file_content);
    std.debug.print("{s}", .{file_content});
}
Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504