Skip to content

Day 71: std.stdio模块:标准IO扩展

我们已经接触过std.io,它提供了Reader和Writer等底层的I/O接口。而std.stdio则是在此基础上构建的更高级、更易于使用的模块。它的API设计与C语言的<stdio.h>库有很多相似之处,提供了诸如文件句柄、缓冲和格式化扫描等功能。

对于日常的文件操作和控制台交互,std.stdio通常比std.io更方便。

std.stdio.File是对std.fs.File的一个包装,它自动处理缓冲,并提供了更丰富的API。

  • File.open(path, mode): 以类似C fopen的模式(如"r", "w", "a")打开一个文件。
  • file.reader() / file.writer(): 获取底层的Reader和Writer接口。
  • file.readByte() / file.writeByte(): 读写单个字节。
  • file.readToEndAlloc(): 读取整个文件内容到堆上分配的内存中。
const std = @import("std");
const stdio = std.stdio;
pub fn main() !void {
const file = try stdio.File.open("hello.txt", .{"w"});
defer file.close();
try file.writer().print("Hello, {s}!\n", .{"stdio"});
}

std.stdio.Scanner是std.stdio中最强大的工具之一。它允许你从一个Reader中解析和提取格式化的数据,类似于C的scanf。

Scanner提供了多种方法来读取不同类型的数据:

  • next(T): 读取下一个由空白符分隔的单元,并尝试将其解析为类型T。
  • nextU64, nextF64, etc.: 特定类型的快速版本。
  • skipWhitespace(): 跳过所有空白字符。
const std = @import("std");
pub fn main() !void {
const input = "123 45.67 hello";
var stream = std.io.fixedBufferStream(input);
var scanner = std.stdio.Scanner{ .reader = stream.reader() };
const my_int = try scanner.next(u64);
const my_float = try scanner.next(f64);
const my_string = try scanner.next([]const u8);
std.debug.print("Int: {d}, Float: {d}, String: {s}\n", .{my_int, my_float, my_string});
}

std.stdio非常适合处理命令行的交互式输入。

const std = @import("std");
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
const stdin_reader = std.io.getStdIn().reader();
try stdout.print("What is your name? ", .{});
var buffer: [100]u8 = undefined;
const line = (try stdin_reader.readUntilDelimiterOrEof(buffer[0..], '\n')) orelse "";
try stdout.print("Hello, {s}!\n", .{line});
try stdout.print("Enter your age: ", .{});
var scanner = std.stdio.Scanner{ .reader = stdin_reader };
const age = try scanner.next(u8);
try stdout.print("You are {d} years old.\n", .{age});
}

给定一个如下格式的CSV字符串:"name1,10\nname2,20\n"。使用std.stdio.Scanner和readUntilDelimiter等函数,编写一个循环来解析每一行,并打印出姓名和分数。

  • 二进制模式 File.open的模式字符串可以包含"b"(例如"rb"或"wb"),以在Windows上禁用换行符转换(\n -> \r\n)。在非Windows系统上,"b"通常被忽略。

  • 缓冲和刷新 std.stdio.File默认是带缓冲的。写入的数据可能不会立即到达磁盘,而是先存储在内存缓冲区中。你可以调用file.flush()来强制将缓冲区的内容写入文件。程序正常退出时,所有缓冲区都会被自动刷新。

  • 管道和重定向 std.io.getStdIn()、getStdOut()和getStdErr()返回的是标准的文件描述符。当用户在shell中使用管道(|)或重定向(>)时,这些描述符会自动指向管道或文件,你的Zig程序无需任何修改即可正确工作。

std.stdio为Zig带来了与C语言<stdio.h>相媲美的便利性和功能性,但具有Zig的类型安全和错误处理机制。它在std.io的底层抽象之上,提供了一套更符合人体工程学的API,用于处理日常的文件和控制台I/O任务。对于需要快速编写脚本或处理格式化文本的场景,std.stdio是一个不可或缺的工具。