这个问题是previous question的延续。我编写了以下代码来确定File.openRead()
是否创建了可以逐行流式传输的Stream。事实证明答案是否定的。读取整个文件,然后传递给下一个转换。我的问题是:你如何在Dart中逐行传输文件?
import 'dart:async';
import 'dart:convert';
import 'dart:io';
void main(List<String> arguments) {
Stream<List<int>> stream = new File('Data.txt').openRead();
stream
.transform(const Utf8InterceptDecoder())
.transform(const LineSplitterIntercept())
.listen((line) {
// stdout.writeln(line);
}).asFuture().catchError((_) => print(_));
}
int lineSplitCount = 0;
class LineSplitterIntercept extends LineSplitter {
const LineSplitterIntercept() : super();
// Never gets called
List<String> convert(String data) {
stdout.writeln("LineSplitterIntercept.convert : Data:" + data);
return super.convert(data);
}
StringConversionSink startChunkedConversion(ChunkedConversionSink<String> sink) {
stdout.writeln("LineSplitterIntercept.startChunkedConversion Count:"+lineSplitCount.toString()+ " Sink: " + sink.toString());
lineSplitCount++;
return super.startChunkedConversion(sink);
}
}
int utfCount = 0;
class Utf8InterceptDecoder extends Utf8Decoder {
const Utf8InterceptDecoder() : super();
//never gets called
String convert(List<int> codeUnits) {
stdout.writeln("Utf8InterceptDecoder.convert : codeUnits.length:" + codeUnits.length.toString());
return super.convert(codeUnits);
}
ByteConversionSink startChunkedConversion(ChunkedConversionSink<String> sink) {
stdout.writeln("Utf8InterceptDecoder.startChunkedConversion Count:"+ utfCount.toString() + " Sink: "+ sink.toString());
utfCount++;
return super.startChunkedConversion(sink);
}
}
答案 0 :(得分:2)
如果需要流,您可以从readAsLines()
返回的未来创建它:
Stream<List<String>> stream =
new Stream.fromFuture(new File('Data.txt').readAsLines());
然而,对于我来说,逐一明确地处理这些行似乎更简单,
List<String> lines = new File('Data.txt').readAsLinesSync();
for (var line in lines) {
stdout.writeln(line);
}
答案 1 :(得分:1)
转换器的startChunkedConversion
仅在转换开始时调用一次。但是,使用文件的一部分多次调用返回的接收器的add
方法。
由消息来决定块的大小,但是37MB的文件(如前一个问题所述)肯定会以较小的块发送。
如果你想看到这些块,你可以截取startChunkedConversion
并返回一个包裹的接收器,或者你可以将自己置于openRead
和变压器之间。
截取:
class InterceptSink {
static int lineSplitCount = 0;
final _sink;
InterceptSink(this._sink);
add(x) {
print("InterceptSink.add Count: $lineSplitCount");
lineSplitCount++;
_sink.add(x);
}
close() { _sink.close(); }
}
class LineSplitterIntercept extends Converter {
convert(x) { throw "unimplemented"; }
startChunkedConversion(outSink) {
var lineSink = new LineSplitter().startChunkedConversion(outSink);
return new InterceptSink(lineSink);
}
}
openRead
之后:
file.openRead()
.transform(UTF8.decoder)
.map(x) {
print("chunk size: ${x.length)");
return x;
}
.transform(new LineSplitter())
...
答案 2 :(得分:1)
因为没有其他答案适合我的情况,所以这是另一种技巧:
import 'dart:io';
import 'dart:convert';
void main()
{
var file = File('/path/to/some/file.txt);
var raf = file.openSync(mode: fileMode.read);
String line;
while ((line = readLine(raf)) != null)
{
print(line);
}
}
String readLine(RandomAccessFile raf, {String lineDelimiter = '\n'}) {
var line = '';
int byte;
var priorChar = '';
var foundDelimiter = false;
while ((byte = raf.readByteSync()) != -1) {
var char = utf8.decode([byte]);
if (isLineDelimiter(priorChar, char, lineDelimiter)) {
foundDelimiter = true;
break;
}
line += char;
priorChar = char;
}
if (line.isEmpty && foundDelimiter == false) {
line = null;
}
return line;
}
bool isLineDelimiter(String priorChar, String char, String lineDelimiter) {
if (lineDelimiter.length == 1) {
return char == lineDelimiter;
} else {
return priorChar + char == lineDelimiter;
}
}
答案 3 :(得分:1)
我认为这段代码很有用:
import 'dart:io';
import 'dart:convert';
import 'dart:async';
main() {
final file = new File('file.txt');
Stream<List<int>> inputStream = file.openRead();
inputStream
.transform(utf8.decoder) // Decode bytes to UTF-8.
.transform(new LineSplitter()) // Convert stream to individual lines.
.listen((String line) { // Process results.
print('$line: ${line.length} bytes');
},
onDone: () { print('File is now closed.'); },
onError: (e) { print(e.toString()); });
}