How do i read and write files efficiently as in c ? Thank you

const std = @import(“std”);

const WIDTH = 800;
const HEIGHT = 600;

var pixels: [WIDTH*HEIGHT]u32 = undefined;

pub fn main() !void {
grig_fill(&pixels, 0xFF00FF00);
try grig_save_as_ppm(&pixels, “pixels.ppm”);
}

fn grig_fill(p: [WIDTHHEIGHT]u32, color: u32) void {
for (0…WIDTHHEIGHT) |i| {
p.
[i] = color;
}
}

fn grig_save_as_ppm(p: [WIDTHHEIGHT]u32, path: []const u8) !void {

var out = try std.fs.cwd().createFile(path, .{});
defer out.close();

try out.writer().print("P6\n{} {} 255\n", .{WIDTH, HEIGHT});

for (p) |pixel| {
    var bytes = [_]u8{
        @intCast((pixel>>(8*0)) & 0xFF), 
        @intCast((pixel>>(8*1)) & 0xFF), 
        @intCast((pixel>>(8*2)) & 0xFF), 
    };
    _ = try out.write(&bytes);
}

}

// this works but its too slow. where as c version is so fast.

2 Likes

I think you can try using BufferedWriter.

const std = @import("std");

const WIDTH = 800;
const HEIGHT = 600;

var pixels: [WIDTH * HEIGHT]u32 = undefined;

pub fn main() !void {
    grig_fill(&pixels, 0xFF00FF00);
    try grig_save_as_ppm(&pixels, "pixels.ppm");
}

fn grig_fill(p: *[WIDTH * HEIGHT]u32, color: u32) void {
    for (0..WIDTH * HEIGHT) |i| {
        p.*[i] = color;
    }
}

fn grig_save_as_ppm(p: *[WIDTH * HEIGHT]u32, path: []const u8) !void {
    var file = try std.fs.cwd().createFile(path, .{});
    defer file.close();

    var out = std.io.bufferedWriter(file.writer());

    try out.writer().print("P6\n{} {} 255\n", .{ WIDTH, HEIGHT });

    for (p) |pixel| {
        var bytes = [_]u8{
            @intCast((pixel >> (8 * 0)) & 0xFF),
            @intCast((pixel >> (8 * 1)) & 0xFF),
            @intCast((pixel >> (8 * 2)) & 0xFF),
        };
        _ = try out.write(&bytes);
    }
}

Additionally, you can add -Doptimize=ReleaseFast when building exe.

4 Likes

You are getting bad performance because you are doing a system call per pixel here:

for (p) |pixel| {
        var bytes = [_]u8{
            @intCast((pixel >> (8 * 0)) & 0xFF),
            @intCast((pixel >> (8 * 1)) & 0xFF),
            @intCast((pixel >> (8 * 2)) & 0xFF),
        };
        _ = try out.write(&bytes);  <------- HERE
    }`

And there are going to be WIDTH * HEIGHT system calls, which is a lot.
So, when using a buffered writer, you are creating a buffer in which your payload is saved (or buffered) until you reach the buffer limit (I think the default is 4096 bytes), and only then is the system call actually done.

2 Likes

…and don’t forget to flush at the end!

try out.flush()

Here’s a good read on the subject: How to Add Buffering to a Reader / Writer in Zig - Zig NEWS

3 Likes

Thank you it works fine now.