如何正确使用Zig的缓冲写入器和读取器,以避免输出不完整或奇怪?

huangapple go评论69阅读模式
英文:

How can I properly use Zig's buffered writer and reader without incomplete or strange output?

问题

当使用缓冲写入器(buffered writer)和读取器(buffered reader)时,我的输出有时会不完整或表现出奇怪的行为。这似乎是由于最终输出消息的字符串格式化引起的。

在按照此教程后,我创建了以下代码。它简单地接受用户输入并返回格式化的消息:

const std = @import("std");

pub fn main() !void {
    // 标准输出的句柄
    const stdout = std.io.getStdOut();
    var bw = std.io.bufferedWriter(stdout.writer());
    const w = bw.writer();

    // 标准输入的句柄
    const stdin = std.io.getStdIn();
    var br = std.io.bufferedReader(stdin.reader());
    var r = br.reader();

    // 初始提示
    try w.print("What is your name?: ", .{});
    try bw.flush();

    var msg_buf: [64]u8 = undefined;
    var msg = try r.readUntilDelimiterOrEof(&msg_buf, '\n');

    if (msg) |m| {
        try w.print("Hello, {s}\n", .{m});
    }
    try bw.flush();
}

程序的功能如预期所示:

What is your name?: Foo                                              
Hello, Foo

然而,当我将 {s}if 语句中的位置更改为以下方式时:

try w.print("Hello, {s}!\n", .{m});

会发生以下情况:

What is your name?: foo                                              
!ello, foo

如果我使用任何其他字符,如 '.',甚至是 ' '(空格),都会发生相同的情况。第一个字符被 {s} 后面的字符替换。我是什么地方出错了导致了这个问题?我还注意到,如果没有 '\n',则根本没有任何输出。try w.print("{s}", .{m}); 将导致在用户输入后什么都不返回。

将格式化放在开头允许输出,但输入消息永远不会显示:

try w.print("{s}! So good to see you\n", .{m});

结果:

What is your name?: Foo                                              
! So good to see you  

我一定是在某些地方错误地使用了缓冲区,并且我相信可以改进此代码以解决此问题。任何帮助或详细的文档都将不胜感激。

英文:

When using the buffered writer and reader, my output is sometimes incomplete or behaves strangely. This is seemingly caused by the string formatting of my final output message.

After following this tutorial I created the following code. It simply takes user input and returns a formatted message:

const std = @import("std");

pub fn main() !void {
    // Handle to the standard output
    const stdout = std.io.getStdOut();
    var bw = std.io.bufferedWriter(stdout.writer());
    const w = bw.writer();

    // Handle to the standard input
    const stdin = std.io.getStdIn();
    var br = std.io.bufferedReader(stdin.reader());
    var r = br.reader();

    // Initial prompt
    try w.print("What is your name?: ", .{});
    try bw.flush();

    var msg_buf: [64]u8 = undefined;
    var msg = try r.readUntilDelimiterOrEof(&msg_buf, '\n');

    if (msg) |m| {
        try w.print("Hello, {s}\n", .{m});
    }
    try bw.flush();
}

The program functions as expected:

What is your name?: Foo                                              
Hello, Foo

However, when I change the location of {s} in the 'if' statement like so:

try w.print("Hello, {s}!\n", .{m});

This happens:

What is your name?: foo                                              
!ello, foo

The same happens if i use any other character such as '.', or even ' ' (space). The first character is replaced by the character after the {s}. What am I doing wrong to cause this issue? I also notice that without '\n', no output occurs at all.
try w.print("{s}", .{m}); will cause nothing to be returned after user input.

Placing the formatting at the beginning allows for output, but the input message is never displayed:

try w.print("{s}! So good to see you\n", .{m});

Result:

What is your name?: Foo                                              
! So good to see you  

I must be misusing the buffers somehow, and I'm sure this code could be improved to alleviate this issue. Any help or detailed documentation would be appreciated.

答案1

得分: 2

从你所遇到的问题来看,我假设你正在使用Windows机器。

{s}之后出现!的奇怪行为是因为Windows使用\r\n作为换行符,而不是Unix的\n。你的代码正确地将\r解释为输入的最后一个字符,当打印这个特殊字符时,会将写入的“光标”移动到行的开头,覆盖已经存在的文本。

你可以通过修整输入字符串来避免这个问题,例如使用标准库函数std.mem.trim

英文:

From the problem you're seeing I assume you're using a Windows machine.

The reason for the weird behaviour with ! after the {s} comes from the fact that Windows uses \r\n as its line ending instead of the Unix \n. Your code correctly reads the \r as the last character of the input and when printing this special character makes the write "cursor" move to the beginning of the line, overwriting the text already present there.

You can avoid this problem by trimming the input string using for example the stdlib function std.mem.trim

huangapple
  • 本文由 发表于 2023年5月21日 04:48:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/76297302.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定