为什么在这个D例子中到达EOF之前还有一个额外的循环?

时间:2014-09-14 11:32:00

标签: io d

以下是官方D书中的一个例子:

import std.stdio;
import std.string;

void main()
{
    File file = File("student_records", "w");

    file.writeln("Name  : ", "Zafer");
    file.writeln("Number: ", 123);
    file.writeln("Class : ", "1A");
    file.close();

    File file1 = File("student_records", "r");

    while (!file1.eof()) {
        string line = (chomp(file1.readln()));
        writeln("read line -> |", line);
    }
}

如果你运行它,你会得到:

ldc2 -run file.d
read line -> |Name  : Zafer
read line -> |Number: 123
read line -> |Class : 1A
read line -> |

注意打印出一个空行。现在,如果我将第三个writeln改为write,

import std.stdio;
import std.string;

void main()
{
    File file = File("student_records", "w");

    file.writeln("Name  : ", "Zafer");
    file.writeln("Number: ", 123);
    file.write("Class : ", "1A");
    file.close();

    File file1 = File("student_records", "r");

    while (!file1.eof()) {
        string line = (chomp(file1.readln()));
        writeln("read line -> |", line);
    }
}

然后不再打印最后一个空行:

ldc2 -run file.d
read line -> |Name  : Zafer
read line -> |Number: 123
read line -> |Class : 1A

我想知道为什么这会产生影响:readln应该读到行的末尾,包括行终止符号,为什么当我们显然达到EOF时应该有一个额外的循环?

1 个答案:

答案 0 :(得分:8)

我的猜测是readln读取并包括行终止符('\n')但不包括EOF。你的文件看起来像这样:

Name  : Zafer\n   <---- first readln
Number: 123\n     <---- second readln
Class : 1A\n      <---- third readln
EOF               <---- fourth readln

readln的第三次调用之后,还有更多内容需要阅读,即使它只是EOF。对readln的最后一次调用返回null,writeln愉快地接受并且不打印任何内容(在字符串“read line - &gt; |”之后)。 docs on readln中给出的示例实际检查readln是否返回null并使用它来终止。

// Reads $(D stdin) and writes it to $(D stdout).
import std.stdio;

void main()
{
    string line;
    while ((line = stdin.readln()) !is null)
        write(line);
}

另一种选择是使用foreach

foreach(line ; file1.byLine) {
    writeln("read line -> |", line.chomp);
}

以上和文档中的示例都避免打印该空行。

如上所述,在创建文件时用writeln替换上一个write也可以避免打印最后一个空行,因为只有一个\n,所以第三次调用{ {1}}直接读到readln而不会在最终EOF停止。