【发布时间】:2015-01-02 19:42:28
【问题描述】:
是否有一种简单的方法可以打开文件并连续读取文件,而不会在 EOF 上关闭流?就像 Unix 命令tail -f。
API 文档中描述了EOF 之前的内容。但我看不到一种明显/简单的方法来阻止或暂停流以获取更多输入。
当我检测到文件大小已更改时,一种解决方案是反复重新打开文件并从最后一个已知长度继续读取。
【问题讨论】:
是否有一种简单的方法可以打开文件并连续读取文件,而不会在 EOF 上关闭流?就像 Unix 命令tail -f。
API 文档中描述了EOF 之前的内容。但我看不到一种明显/简单的方法来阻止或暂停流以获取更多输入。
当我检测到文件大小已更改时,一种解决方案是反复重新打开文件并从最后一个已知长度继续读取。
【问题讨论】:
这样想
import 'dart:io';
void main(List<String> args ) {
var file = new File("test.txt");
print(file.absolute);
var openFuture = file.open(mode: FileMode.READ);
openFuture.then((raf) => raf.length().then((len) => raf.setPosition(len)
.then((raf) => raf.readXxx...
}
您还可以使用Directory.watch 来获取有关更改的通知,然后重新打开并从最后一个已知位置读取。
【讨论】:
(尽管这个问题现在已经有很多年了,但我今天偶然发现了同样的问题并且找不到可行的解决方案,因此不得不推出自己的解决方案,并希望与未来几代的 Dart 程序员分享我的发现. ;-))
dart:io 包与一些流和 async-await 魔法相结合应该提供实现类似“tail -f”功能所需的一切:
import 'dart:typed_data';
import 'dart:io';
Stream<List<int>> tail(final File file) async* {
final randomAccess = await file.open(mode: FileMode.read);
var pos = await randomAccess.position();
var len = await randomAccess.length();
// Increase/decrease buffer size as needed.
var buf = Uint8List(8192);
Stream<Uint8List> _read() async* {
while (pos < len) {
final bytesRead = await randomAccess.readInto(buf);
pos += bytesRead;
yield buf.sublist(0, bytesRead);
}
}
// Step 1: read whole file
yield* _read();
// Step 2: wait for modify events and read more bytes from file
await for (final event in file.watch(events: FileSystemEvent.modify)) {
if ((event as FileSystemModifyEvent).contentChanged) {
len = await (randomAccess.length());
yield* _read();
}
}
}
这个函数 (tail) 可以这样使用:
import 'dart:convert';
import 'dart:io';
void main() {
final file = File('/var/log/messages');
tail(file).transform(utf8.decoder).transform(LineSplitter()).forEach((line) {
// Do something with the line that has been read, e.g. print it out...
print(line);
});
}
【讨论】: