项目:读取文件并计算字节数
Buffer,文件I/O,链接故障处理和内存释放。
Wave Foundation
准备好了
在工作目录中创建 input.txt,其中包含 Wave,后跟单个 LF 换行符。该文件包含 5 个字节。 CRLF 包含 6 个字节; UTF-8 BOM 添加更多字节。检查编辑器的文件编码和行结尾。
将程序保存为main.wave,并从同一目录中以wavec run main.wave 运行。相对路径是相对于正在运行的工作目录的。
import("std::buffer::alloc")::{
Buffer, buffer_init, buffer_free
};
import("std::fs::file")::{
read_to_end
};
fun main() -> i32 {
var data: Buffer;
if (buffer_init(&data, 0) < 0) {
return 1;
}
var count: i64 = read_to_end("input.txt", &data);
if (count < 0) {
println("read failed={}", count);
buffer_free(&data);
return 2;
}
var lines: i64 = 0;
for (var i: i64 = 0; i < data.len; i += 1) {
if (deref data.data[i] == 10) {
lines += 1;
}
}
println("bytes={} LF={}", count, lines);
if (buffer_free(&data) < 0) {
return 3;
}
return 0;
}
执行结果:
bytes=5 LF=1
行动和责任
read_to_end 打开和关闭文件,但 Buffer 释放是调用者的责任。关闭成功和读取失败路径。由于它是多个字节的数据,因此我们不假设它是以NUL结尾的字符串。
LF 行数和人们想象的行数并不总是一样的。如果最后一行不包含 LF,则不包含在该程序的 LF 计数中。还可以通过重命名文件来检查读取失败。具体错误号可能会因您的环境而异。
扩展练习和评论
如果要处理非常大的文件,请将其替换为固定大小的数组和io_read迭代。仅处理正返回范围并在 0 处终止。您可以累积字节计数和 LF 计数,而无需将整个文件保留在内存中。如果您自己打开它,它还会关闭任何退出路径上的描述符。
遵循处理流程
- 初始化 bin Buffer。还没有文件内容。
- read_to_end 读取文件并增加所需空间。
- 如果读取成功,则检查data.len范围内的字节。
- 每当我们遇到LF的字节值10时,我们就会递增lines。
- 打印结果并发布Buffer。
data.cap 为预留存储空间,data.len 为有效数据长度。如果将重复条件更改为cap,则会读取文件中没有的字节,因此请使用len。 count 是本次调用read_to_end 添加的字节数。此示例以空的 Buffer 开头,因此 count 和 data.len 相等。
更改输入以检查
| input.txt 内容 | bytes | LF | 原因 |
|---|---|---|---|
| 空文件 | 0 | 0 | 没有字节可读取 |
Wave |
4 | 0 | 最后没有换行 |
Wave + LF |
5 | 1 | 截至最后的数据LF |
A + LF + B + LF |
4 | 2 | 数二LF |
Wave + CRLF |
6 | 1 | CR也是1个字节,但是只计算LF。 |
要将最后一行没有 LF 的文件算作一行,如果文件不为空且最后一个字节不为 10,则行数加 1。必须先检查 data.len 是否为 0,然后才能访问最后一个元素。
扩展到大文件
目前将全部内容存档的方法方便以后重新阅读或检索数据。如果您只需要字节数和 LF 计数,则重用固定大小的缓冲区是有意义的。
在 将文件读入固定大小的缓冲区 示例中的 io_read 循环中,只需按返回的字节数计算 LF 即可。它可以使用等于缓冲区大小的内存进行处理,而不是文件的整个长度。如果读取返回0,则结束;如果为负,则表示错误。