Create/write file
Suppose we want to create a file named sample.txt in the current directory. To do that you can do this:
const std = @import("std");
test "Create/write file" {
var file = try std.fs.cwd().createFile("sample.txt", .{});
defer file.close();
_ = try file.write("Hello, world!\n");
_ = try file.write("Nice day we're having today.\n");
_ = try file.write("What have you been up to lately?\n");
_ = try file.write("H-hey, why did you pull out that knife...?\n");
const Writer = file.writer();
const phone_number = 911;
try Writer.print("Help! Someone, please call {d}!\n\n", .{phone_number});
}
$ zig test file.zig
All 1 tests passed.
$ cat sample.txt
Hello, world!
Nice day we're having today.
What have you been up to lately?
H-hey, why did you pull out that knife...?
Help me! Someone, please call 911!
$ █
Append data to file
However, createFile()
by default will overwrite
the existing file. If you wish to append to the file instead,
do this:
....
var file = try std.fs.cwd().createFile("sample.txt", .{ .truncate = false });
// or this:
var file = try std.fs.cwd().openFile("sample.txt", .{ .write = true });
defer file.close();
// Set the current position of the file to the end.
try file.seekFromEnd(0);
....
$ zig test file.zig
All 1 tests passed.
$ cat sample.txt
Hello, world!
Nice day we're having today.
What have you been up to lately?
H-hey, why did you pull out that knife...?
Help me! Someone, please call 911!
Hello, world!
Nice day we're having today.
What have you been up to lately?
H-hey, why did you pull out that knife...?
Help me! Someone, please call 911!
$ █
Check if a file exists
One way to check whether a file exists or not is by calling
openFile()
and catch if it returns an
error.FileNotFound
instead.
// Given the following list of files:
// .
// ├─ file.zig
// └─ sample.txt
const std = @import("std");
fn fileExists(path: []const u8) !bool {
const file = std.fs.cwd().openFile(path, .{}) catch |err| switch (err) {
error.FileNotFound => return false,
else => return err,
};
file.close();
return true;
}
test "Check if a file exists" {
try std.testing.expect(try fileExists("sample.txt"));
try std.testing.expect(!try fileExists("does_not_exist.txt"));
}
$ zig test file.zig
All 1 tests passed.
$ █
Read file
To read a file and store its entire data inside a slice of bytes using heap allocation, we do this:
const std = @import("std");
pub fn main() !void {
const allocator = std.heap.page_allocator;
const max_size = std.math.maxInt(usize);
var data = try std.fs.cwd().readFileAlloc(allocator, "sample.txt", max_size);
defer allocator.free(data);
const printToStdout = std.io.getStdOut().writer().print;
printToStdout("{s}", .{data}) catch {};
}
$ zig build-exe file.zig
$ ./file
Hello, world!
Nice day we're having today.
What have you been up to lately?
H-hey, why did you pull out that knife...?
Help! Someone, please call 911!
Hello, world!
Nice day we're having today.
What have you been up to lately?
H-hey, why did you pull out that knife...?
Help! Someone, please call 911!
$ █
Read file in small chunks
In case you're dealing with a huge file, or you simply just want to read the file in certain bytes at a time, you can instead use a stack-allocated buffer, like so:
const std = @import("std");
pub fn main() !void {
const file = try std.fs.cwd().openFile("sample.txt", .{});
defer file.close();
const printToStdout = std.io.getStdOut().writer().print;
var buffer: [64]u8 = undefined;
// Or use heap-allocated buffer instead.
//var buffer = try std.heap.page_allocator.alloc(u8, 64);
//defer std.heap.page_allocator.free(buffer);
var file_size: usize = 0;
while (true) {
const bytes_read = try file.read(&buffer);
if (bytes_read == 0)
break;
file_size += bytes_read;
printToStdout("{s}", .{buffer[0 .. bytes_read]}) catch {};
}
printToStdout("\nFile size is {d} bytes\n", .{file_size}) catch {};
}
$ zig build-exe file.zig
$ ./file
Hello, world!
Nice day we're having today.
What have you been up to lately?
H-hey, why did you pull out that knife...?
Help! Someone, please call 911!
Hello, world!
Nice day we're having today.
What have you been up to lately?
H-hey, why did you pull out that knife...?
Help! Someone, please call 911!
File size is 304 bytes
$ █
Read/write file
By default, all files opened with openFile()
are
read-only. If you want to modify them, you have to pass the
option .{ .write = true }
first.
const std = @import("std");
test "Read/write file" {
const file = try std.fs.cwd().openFile("sample.txt", .{ .write = true });
defer file.close();
const file_size = try file.getEndPos();
while (true) {
const current_position = try file.getPos();
if (current_position + 4 >= file_size)
break;
try file.seekBy(4);
try file.writer().writeByte('a');
}
}
$ zig test file.zig
All 1 tests passed.
$ cat sample.txt
Hella, woald!
aice aay wa're aavina today.
Waat have yau bean upato latelya
H-hay, way dia youapullaout ahat anifea..?
aelp!aSomeane, aleasa cala 911a
Healo, aorlda
Nica dayawe'ra havang taday.aWhatahaveayou aeen ap toalateay?
Hahey,awhy aid yau pual oua thaa kniae...a
Hela! Soaeonea please call 9a1!
$ █
Delete file
Deleting a file is very easy.
// Given the following list of files:
// .
// ├─ file.zig
// └─ sample.txt
const std = @import("std");
test "Delete file" {
std.fs.cwd().deleteFile("sample.txt") catch |err| switch (err) {
error.FileNotFound => {},
else => return err,
};
const has_been_deleted = std.fs.cwd().openFile("sample.txt", .{});
try std.testing.expectError(error.FileNotFound, has_been_deleted);
}
$ zig test file.zig
All 1 tests passed.
$ █