#Read a file into a std.ArrayList(std.ArrayList(u8))

1 messages · Page 1 of 1 (latest)

bitter maple
#

I see when you open a file you can do file.reader().readAllArrayList, I was wondering if I can do the same but instead to read line by line into a std.ArrayList(std.ArrayList(u8))

#

or if that doesn't exist, what's the most efficent way to do it

bitter maple
#

so I did this

            var wrote = false;

            while (try file.reader().readUntilDelimiterOrEofAlloc(allocator, '\n', std.math.maxInt(usize))) |line| {
                defer allocator.free(line);
                try std.fs.cwd().writeFile("x.txt", line);
                wrote = true;
                var arr = std.ArrayList(u8).init(allocator);
                errdefer arr.deinit();

                try arr.appendSlice(line);
                try tab.buf.append(arr);
            }

            if (!wrote) {
                try tab.buf.append(std.ArrayList(u8).init(allocator));
            }
        }```
fiery root
#

i don't see any reason to use a list of lists. maybe use a list of slices

const std = @import("std");
test {
    const allocator = std.testing.allocator;
    const file = try std.fs.cwd().openFile("/tmp/tmp.zig", .{});
    var lines = std.ArrayList([]const u8).init(allocator);
    defer {
        for (lines.items) |line| allocator.free(line);
        lines.deinit();
    }
    while (try file.reader().readUntilDelimiterOrEofAlloc(allocator, '\n', std.math.maxInt(u32))) |line| {
        try lines.append(line);
    }
    for (lines.items) |line| std.debug.print("line={s}\n", .{line});
}
bitter maple
#

where I will be constantly changing bytes on each line

fiery root
#

oh ok let me adjust it...

bitter maple
#

it seemed a little rude for me, please ask next time instead of instantly sending a solution

#

it's just me, you weren't rude

fiery root
#

seems like for an editor, you'd want to re-use the memory as much as possible?

bitter maple
#

and optimize it later

#

i just want it working first

fiery root
#

i think this does a decent job of re-using memory. i'm sure it could be improved, but maybe its interesting

const std = @import("std");
test {
    const allocator = std.testing.allocator;
    const file = try std.fs.cwd().openFile("/tmp/tmp.zig", .{});
    var lines = std.ArrayList(std.ArrayListUnmanaged(u8)).init(allocator);
    defer {
        for (lines.items) |*line| line.deinit(allocator);
        lines.deinit();
    }
    // simulate reading the file a few times
    for (0..5) |_| {
        try file.seekTo(0);
        var linei: usize = 0;
        while (true) : (linei += 1) {
            // re-use existing line if available
            const line = if (linei < lines.items.len) blk: {
                lines.items[linei].clearRetainingCapacity();
                break :blk &lines.items[linei];
            } else blk: {
                const newline = try lines.addOne();
                newline.* = .{};
                break :blk newline;
            };

            // std.debug.print("linei={} lines={}/{} line={*}\n", .{ linei, lines.items.len, lines.capacity, lines.items.ptr });
            file.reader().streamUntilDelimiter(line.writer(allocator), '\n', null) catch |e| switch (e) {
                error.EndOfStream => break,
                else => return e,
            };
        }
        lines.items.len = linei;
    }
    for (lines.items) |line| std.debug.print("line={s}\n", .{line.items});
}
bitter maple
#

holy she

#

thanks

fiery root
#

streamUntilDelimiter() is pretty nice for this

#

i think this line is necessary for when the previous lines were longer than current lines: lines.items.len = linei;

#

and i chose to use std.ArrayList(std.ArrayListUnmanaged(u8)) so that the inner lists can be a little smaller - don't need to store the allocator field for every line.

fiery root
#

i do see one problem with that code. this will leak memory when there were previously more lines than current.

defer {
    for (lines.items) |*line| line.deinit(allocator);
    lines.deinit();
}
#

maybe you could just use an arena to fix that