#Reading From a File in Zig

1 messages · Page 1 of 1 (latest)

fallen berry
#

Hello,

I'm looking for something akin to a fscanf() replacement in Zig. I have the following C code:

        // Open the file specified by the i-1th argument
        FILE* fp = fopen(argv[i - 1], "r");

        // Loop through each row in the file
        for (j = 0; j < COLS; j++) {
            // Read a value from the file and store it in sold[i-2][j]
            fscanf(fp, "%*d %*s %d", &x);
            sold[i - 2][j] = x;
        }

        // Close the file
        fclose(fp);

which you can see loops through the rows in a file and pulls out integers in the third column. How can I do a similar thing in Zig?

#

Sorry, I must go for a while but I'll be back on this thread to check up on it soon!

severe schooner
#

It's not entirely clear to me why you have three format specifiers (%*d, %*s, %d) but yet only one output pointer (&x)
But then I haven't used scanf functions in a while. 😄

Generally, in Zig, you'd just write the parsing code you need.
In this case, maybe splitting by line then using std.fmt.parseInt.
There's no direct equivalent to scanf functions in Zig at present.

You could read line by line via things like file.reader().streamUntilDelimiter, file.reader().readUntilDelimiterOrEof, or file.reader().readUntilDelimiterOrEofAlloc.
Though, I generally suggest just reading the entire file into memory first, because it's simpler.
You can also get a reader from a slice via std.io.fixedBufferStream(slice) if it's wanted.

brittle kite
fallen berry
#

But I'm assuming someone has written code to parse a file already, right? & is there something like the FILE* in C?

brittle kite
#

only the parsing part that scanf handles you have to do yourself

#

you can use the reader() on a File which has a few convenient functions

floral warren
#

std.mem.tokenize and it's variants will probably be good to look if you are reading the whole file, it returns an iterator that collapses multiple copies of the given delimiter. With tokenizeAll, it collapses all delimiters even if they are different ones, so it can help with files that are not uniformly separated.

#

This reads the file contents into a slice of a struct that maps to the columns of information that are separated by any number of tabs or spaces: ```rs

const Data = struct { num1: i32, label1: []const u8, num2: i32 };

pub fn main() !void {
var file_content =
"123 stuff 456\n-42 \t kjhasdkjhldkjhf 222\n420\t\tnice 69";

var data = std.ArrayList(Data).init(std.heap.page_allocator);
defer data.deinit();

var cols = std.mem.tokenizeAny(u8, file_content, " \t\n");
while (cols.peek()) |_| {
    try data.append(.{
        .num1 = try std.fmt.parseInt(i32, cols.next().?, 10),
        .label1 = cols.next().?,
        .num2 = try std.fmt.parseInt(i32, cols.next().?, 10),
    });
}

std.debug.print("{any}\n", .{try data.toOwnedSlice()});

}

#

That is an example of one way to do it, if you know your input is not malformed.