How to read a file line by line in Dart - dart

This question is a continuation of a previous question. I wrote the following piece of code to determine if File.openRead() created a Stream that could be streamed line-by-line. It turns out that the answer is no. The entire file is read and then passed to the next transform. My question is then: How do you Stream a file line-by-line in 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);
}
}

I think this code is useful:
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()); });
}

If a stream is necessary, you can create it from the future that readAsLines() returns:
Stream<List<String>> stream =
new Stream.fromFuture(new File('Data.txt').readAsLines());
However it looks simpler to me to plainly process the lines one by one,
List<String> lines = new File('Data.txt').readAsLinesSync();
for (var line in lines) {
stdout.writeln(line);
}

The converter's startChunkedConversion is only called once, when the transformation is started. However, the returned sink's add method is invoked multiple times with parts of the file.
It's up to the source to decide how big the chunks are, but a 37MB file (as mentioned in your previous question) will definitely be sent in smaller chunks.
If you want to see the chunks you can either intercept startChunkedConversion and return a wrapped sink, or you can put yourself between the openRead and the transformer.
Intercept:
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);
}
}
After openRead:
file.openRead()
.transform(UTF8.decoder)
.map(x) {
print("chunk size: ${x.length)");
return x;
}
.transform(new LineSplitter())
...

Because none of the other answers suited my situation, here is another technique:
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;
}
}

Adjusting Brett Sutton's answer for sound null safety and wider availability:
import 'dart:io';
import 'dart:convert';
bool isLineDelimiter(String priorChar, String char, String lineDelimiter)
{
if (lineDelimiter.length == 1) {
return char == lineDelimiter;
} else {
return priorChar + char == lineDelimiter;
}
}
/// Reads one line and returns its contents.
///
/// If end-of-file has been reached and the line is empty null is returned.
String? readLine(RandomAccessFile raf,
{String lineDelimiter = '\n', void Function()? onEOF}) {
String line = '';
int byte;
String priorChar = '';
byte = raf.readByteSync();
while (byte != -1) {
String char = utf8.decode([byte]);
if (isLineDelimiter(priorChar, char, lineDelimiter)) return line;
line += char;
priorChar = char;
byte = raf.readByteSync();
}
onEOF?.call();
if (line.isEmpty) return null;
return line;
}
EDIT 1:
I wanted to add some more line-specific functions I made:
/// Skips one line and returns the last byte read.
///
/// If end-of-file has been reached -1 is returned.
int skipLine(RandomAccessFile raf,
{String lineDelimiter = '\n', void Function()? onEOF}) {
int byte;
String priorChar = '';
byte = raf.readByteSync();
while (byte != -1) {
String char = utf8.decode([byte]);
if (isLineDelimiter(priorChar, char, lineDelimiter)) return byte;
priorChar = char;
byte = raf.readByteSync();
}
return byte;
}
/// Reads all lines in the file and executes [onLine] per each.
///
/// If [onLine] returns true the function terminates.
void processLines(
RandomAccessFile raf, {
String lineDelimiter = '\n',
required bool? Function(String line, bool eofReached) onLine,
}) {
bool _eofReached = false;
do {
String? _line;
_line = readLine(raf,
lineDelimiter: lineDelimiter, onEOF: () => _eofReached = true);
if (_line == null) return;
if (onLine(_line, _eofReached) == true) return;
} while (!_eofReached);
}

Related

How to return two value from a function in dart?

here is my code
import 'dart:io';
import 'dart:math';
void main() {
bool flag = false;
for (int i = 0; i < 100; i++) {
gameCode();
if (userNumber == computerNumber) {
flag = true;
break;
}
}
}
int randomNumber(number) {
Random randNumber = Random();
int random = randNumber.nextInt(number);
return random;
}
gameCode() {
int computerNumber = randomNumber(9);
print("start guessing the number : ");
int userNumber = int.parse(stdin.readLineSync()!);
if (userNumber == computerNumber) {
print("You got it");
}
}
in this code you can see gameCode function. in that function there is two value that i need to use in main function.so how do i return those two keyword from that function ?
//userNumber // computerNumber
this is the variable that i want to return from that code
Dart not support return multiple values in function, you can return it with array, map, or you can use third lib tuple
Dart does not support returning multiple values in the current latest version. I would in your case recommend creating a class for the specific purpose of define the result from gameCode(). So something like this:
class GameCodeResult {
int userNumber;
int computerNumber;
GameCodeResult({
required this.userNumber,
required this.computerNumber,
});
}
Which we can then use like this in your program:
import 'dart:io';
import 'dart:math';
void main() {
bool flag = false;
for (int i = 0; i < 100; i++) {
GameCodeResult result = gameCode();
if (result.userNumber == result.computerNumber) {
flag = true;
break;
}
}
}
final _random = Random();
int randomNumber(int maxNumber) => _random.nextInt(maxNumber);
GameCodeResult gameCode() {
int computerNumber = randomNumber(9);
print("start guessing the number : ");
int userNumber = int.parse(stdin.readLineSync()!);
if (userNumber == computerNumber) {
print("You got it");
}
return GameCodeResult(userNumber: userNumber, computerNumber: computerNumber);
}
Note, I also fixed your randomNumber() method since it is not recommended to generate a new Random() object for each new random number you want. We should instead reuse an instance of Random in our program.
Please refer to below code
import 'dart:io';
import 'dart:math';
void main() {
bool flag = false;
for (int i = 0; i < 100; i++) {
Map<String, dynamic> res = gameCode();
print(res);
if (res['user_number'] == res['computer_number']) {
flag = true;
break;
}
}
}
int randomNumber(number) {
Random randNumber = Random();
int random = randNumber.nextInt(number);
return random;
}
Map<String, dynamic> gameCode() {
int computerNumber = randomNumber(9);
print("start guessing the number : ");
int userNumber =
int.parse(stdin.readLineSync()!);
if (userNumber == computerNumber) {
print("You got it");
}
return {
"computer_number": computerNumber,
"user_number": userNumber,
};
}

How to convert a GLib.Value of type GStrv (string[]) to a GLib.Variant

In the following example one class property is of type Gstrv.
With ObjectClass.list_properties() one can query the Paramspec of all properties, and with get_property() all properties can be requested as GLib.Value. How would I access the Value of type GStrv and convert it to a GLib.Variant?
My GLib version is slightly outdated, so I do not have the GLib.Value.to_variant() function available yet :( .
public class Foo: GLib.Object {
public GLib.HashTable<string, int32> bar;
public Foo() {
bar = new GLib.HashTable<string, int32>(str_hash, str_equal);
}
public string[] bar_keys { owned get { return bar.get_keys_as_array(); } }
}
int main() {
var foo = new Foo();
Type type = foo.get_type();
ObjectClass ocl = (ObjectClass) type.class_ref ();
foreach (ParamSpec spec in ocl.list_properties ()) {
print ("%s\n", spec.get_name ());
Value property_value = Value(spec.value_type);
print ("%s\n", property_value.type_name ());
foo.get_property(spec.name, ref property_value);
// next: convert GLib.Value -> GLib.Variant :(
}
foo.bar.set("baz", 42);
return 0;
}
Output:
bar-keys
GStrv
Using GLib.Value.get_boxed() seems to be working.
Example:
// compile simply with: valac valacode.vala
public class Foo: GLib.Object {
public GLib.HashTable<string, int32> bar;
public Foo() {
bar = new GLib.HashTable<string, int32>(str_hash, str_equal);
}
public string[] bar_keys { owned get { return bar.get_keys_as_array(); } }
}
public Variant first_gstrv_property_as_variant(Object obj)
{
Type class_type = obj.get_type();
ObjectClass ocl = (ObjectClass) class_type.class_ref ();
foreach (ParamSpec spec in ocl.list_properties ()) {
print ("%s\n", spec.get_name ());
Value property_value = Value(spec.value_type);
print ("%s\n", property_value.type_name ());
obj.get_property(spec.name, ref property_value);
// next: convert GLib.Value -> GLib.Variant
if(property_value.type_name () == "GStrv") {
return new GLib.Variant.strv((string[])property_value.get_boxed());
}
}
return new GLib.Variant("s", "No property of type GStrv found");
}
int main() {
var foo = new Foo();
print("%s\n", first_gstrv_property_as_variant(foo).print(true));
foo.bar.set("baz", 42);
print("%s\n", first_gstrv_property_as_variant(foo).print(true));
foo.bar.set("zot", 3);
print("%s\n", first_gstrv_property_as_variant(foo).print(true));
return 0;
}
Output:
bar-keys
GStrv
#as []
bar-keys
GStrv
['baz']
bar-keys
GStrv
['baz', 'zot']
In the generated c-code this looks as follows:
_tmp18_ = g_value_get_boxed (&property_value);
_tmp19_ = g_variant_new_strv ((gchar**) _tmp18_, -1);
Passing -1 as length to g_variant_new_strv() means the string array is considered as null terminated. Inside g_variant_new_strv() the g_strv_length() function is used to determine the length.
Hopefully it will be useful to someone else someday. :-)

How to combine traditional and Future-based API in one interface in Dart?

I would like to parse binary file (from some old game) as on desktop as in browser.
So, I should use abstract class, which can read binary data from array of bytes:
abstract class BinData {
int readByte();
String readNullString(){
var buffer = new StringBuffer();
int char;
do {
char = readByte();
if (char == 0){
break;
}
buffer.writeCharCode(char);
} while(true);
return buffer.toString();
}
}
Now I can implement my parser. For example:
class Parser {
BinData _data;
void load(BinData data){
...
}
}
For desktop console application I use dart:io RandomAccessFile:
class FileBinData extends BinData {
RandomAccessFile _file;
FileBinData.from(RandomAccessFile file){
this._file = file;
}
int readByte(){
return this._file.readByteSync();
}
}
For web application I have to use dart:html FileReader. However, this class has only Future-based API, which isn't compatible with my interface:
class WebFileBinData extends BinData {
File _file;
int _position = 0;
WebFileBinData.from(File file){
this._file = file;
}
int readByte(){
Blob blob = _file.slice(_position, _position + 1);
FileReader reader = new FileReader();
var future = reader.onLoad.map((e)=>reader.result).first
.then((e) { ... });
reader.readAsArrayBuffer(blob);
...
}
}
How can I solve it?
Your readByte() should return Future<int> instead of int. You can return a Future from a function/method even when it doesn't do any async operation (return new Future.value(5);) but you can not return int (or any non-Future value) from a function which executes async operations, at least not when the value should be returned as result of the async operation.
You also need to ensure to connect all async calls.
Future<int> readByte(){
return reader.onLoad.map((e)=>reader.result).first
.then((e) {
...
return reader.readAsArrayBuffer(blob);
});
** readNullString
Future<String> readNullString() {
var buffer = new StringBuffer();
int char;
return Future.doWhile(() {
return readByte().then((char) {
if (char == 0) {
return false; // end doWhile
}
buffer.writeCharCode(char);
return true; // continue doWhile
});
}).then((_) => buffer.toString()); // return function result
}

How do I pretty-print productions and line numbers, using ANTLR4?

I'm trying to write a piece of code that will take an ANTLR4 parser and use it to generate ASTs for inputs similar to the ones given by the -tree option on grun (misc.TestRig). However, I'd additionally like for the output to include all the line number/offset information.
For example, instead of printing
(add (int 5) '+' (int 6))
I'd like to get
(add (int 5 [line 3, offset 6:7]) '+' (int 6 [line 3, offset 8:9]) [line 3, offset 5:10])
Or something similar.
There aren't a tremendous number of visitor examples for ANTLR4 yet, but I am pretty sure I can do most of this by copying the default implementation for toStringTree (used by grun). However, I do not see any information about the line numbers or offsets.
I expected to be able to write super simple code like this:
String visit(ParseTree t) {
return "(" + t.productionName + t.visitChildren() + t.lineNumber + ")";
}
but it doesn't seem to be this simple. I'm guessing I should be able to get line number information from the parser, but I haven't figured out how to do so. How can I grab this line number/offset information in my traversal?
To fill in the few blanks in the solution below, I used:
List<String> ruleNames = Arrays.asList(parser.getRuleNames());
parser.setBuildParseTree(true);
ParserRuleContext prc = parser.program();
ParseTree tree = prc;
to get the tree and the ruleNames. program is the name for the top production in my grammar.
The Trees.toStringTree method can be implemented using a ParseTreeListener. The following listener produces exactly the same output as Trees.toStringTree.
public class TreePrinterListener implements ParseTreeListener {
private final List<String> ruleNames;
private final StringBuilder builder = new StringBuilder();
public TreePrinterListener(Parser parser) {
this.ruleNames = Arrays.asList(parser.getRuleNames());
}
public TreePrinterListener(List<String> ruleNames) {
this.ruleNames = ruleNames;
}
#Override
public void visitTerminal(TerminalNode node) {
if (builder.length() > 0) {
builder.append(' ');
}
builder.append(Utils.escapeWhitespace(Trees.getNodeText(node, ruleNames), false));
}
#Override
public void visitErrorNode(ErrorNode node) {
if (builder.length() > 0) {
builder.append(' ');
}
builder.append(Utils.escapeWhitespace(Trees.getNodeText(node, ruleNames), false));
}
#Override
public void enterEveryRule(ParserRuleContext ctx) {
if (builder.length() > 0) {
builder.append(' ');
}
if (ctx.getChildCount() > 0) {
builder.append('(');
}
int ruleIndex = ctx.getRuleIndex();
String ruleName;
if (ruleIndex >= 0 && ruleIndex < ruleNames.size()) {
ruleName = ruleNames.get(ruleIndex);
}
else {
ruleName = Integer.toString(ruleIndex);
}
builder.append(ruleName);
}
#Override
public void exitEveryRule(ParserRuleContext ctx) {
if (ctx.getChildCount() > 0) {
builder.append(')');
}
}
#Override
public String toString() {
return builder.toString();
}
}
The class can be used as follows:
List<String> ruleNames = ...;
ParseTree tree = ...;
TreePrinterListener listener = new TreePrinterListener(ruleNames);
ParseTreeWalker.DEFAULT.walk(listener, tree);
String formatted = listener.toString();
The class can be modified to produce the information in your output by updating the exitEveryRule method:
#Override
public void exitEveryRule(ParserRuleContext ctx) {
if (ctx.getChildCount() > 0) {
Token positionToken = ctx.getStart();
if (positionToken != null) {
builder.append(" [line ");
builder.append(positionToken.getLine());
builder.append(", offset ");
builder.append(positionToken.getStartIndex());
builder.append(':');
builder.append(positionToken.getStopIndex());
builder.append("])");
}
else {
builder.append(')');
}
}
}

Sorting an array of String in BlackBerry

I need to sort an array of String like the following, in ascending order.
String str[] = {"ASE", "LSM", "BSE", "LKCSE", "DFM"};
How to do that? I need help.
This answer is based on Signare and HeartBeat's suggestion. Explore this link for details. Also this link, Sorting using java.util.Array might be helpful.
// Initialization of String array
String strs[] = {"One", "Two", "Threee", "Four", "Five", "Six", "Seven"};
// implementation of Comparator
Comparator strComparator = new Comparator() {
public int compare(Object o1, Object o2) {
return o1.toString().compareTo(o2.toString());
}
};
// Sort
Arrays.sort(strs, strComparator);
Try this -
import java.util.*;
import java.io.*;
public class TestSort1 {
String [] words = { "RĂ©al", "Real", "Raoul", "Rico" };
public static void main(String args[]) throws Exception {
try {
Writer w = getWriter();
w.write("Before :\n");
for (String s : words) {
w.write(s + " ");
}
java.util.Arrays.sort(words);
w.write("\nAfter :\n");
for (String s : words) {
w.write(s + " ");
}
w.flush();
w.close();
}
catch(Exception e){
e.printStackTrace();
}
}
// useful to output accentued characters to the console
public static Writer getWriter() throws UnsupportedEncodingException {
if (System.console() == null) {
Writer w =
new BufferedWriter
(new OutputStreamWriter(System.out, "Cp850"));
return w;
}
else {
return System.console().writer();
}
}
}
Here is my solution:-
String str[]={"ASE","LSM","BSE","LKCSE","DFM"};
for(int j = 0; j < str.length; j++){
for(int i = j + 1; i < str.length; i++) {
if(str[i].compareTo(str[j]) < 0) {
String t = str[j];
str[j] = str[i];
str[i] = t;
}
}
}

Resources