This code is trying to open an existing file, then add text to it via openWrite.
import 'dart:io';
main() {
File inFile = new File('/tmp/foo.txt');
String currentText = inFile.readAsStringSync();
var writer = inFile.openWrite();
writer.write(currentText);
writer.write("\nOne more line");
writer.close();
exit(0);
}
After completion the file is empty. If the exit(0) is not there it works fine.
What call(s) should be done to ensure all writes are written before exit?
Since the writer is async, you will want to use the done property of the writer to be notified when the writing and closing of the stream is done. For instance:
import 'dart:io';
main() {
File inFile = new File('/tmp/foo.txt');
String currentText = inFile.readAsStringSync();
var writer = inFile.openWrite();
writer.write(currentText);
writer.write("\nOne more line");
writer.close();
writer.done.then((_) {
exit(0);
});
}
According to the document, data may be buffered, you shoud await writer.flush(); to make sure data is written to file.
Related
I'm trying to do something like this:
Future<String> getOutAndAnswer(testcase) async {
Process python = await Process.start('python', ['tasks/histogram/run.py']);
Process java = await Process.start('java', ['solutions/Histogram.java']);
String results = "";
for(int i = 0; i < testcase; i++){
final String out = await python.stdout.transform(utf8.decoder).first;
java.stdin.writeln(out);
final String answer = await java.stdout.transform(utf8.decoder).first;
python.stdin.writeln(answer);
results += "($out, $answer)";
}
return results;
}
Basically, the python program is responsible for generating the input of each test case, then the java program will take the input and return the answer, which is sent to the python program to check if it's correct or not, and so on for every test case.
But when I try to use the above code I get an error saying I've already listened to the stream once:
Exception has occurred.
StateError (Bad state: Stream has already been listened to.)
Python program:
import os
CASE_DIR = os.path.join(os.path.dirname(__file__), "cases")
test_cases = next(os.walk(CASE_DIR))[2]
print(len(test_cases))
for case in sorted(test_cases):
with open(os.path.join(CASE_DIR, case), 'r') as f:
print(f.readline(), end='', flush=True)
f.readline()
expected_output = f.readline()
user_output = input()
if expected_output != user_output:
raise ValueError("Wrong answer!")
print("EXIT", flush=True)
Java program:
public class Histogram {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int t = scanner.nextInt();
for (int i = 0; i < t; i++) {
String input = scanner.nextLine();
String answer = calculateAnswer(input);
System.out.println(answer);
}
}
}
Your issue is with .first which is going to listen to the stream, get the first element, and then immediately stop listening to the stream. See the documentation here: https://api.dart.dev/stable/2.17.3/dart-async/Stream/first.html
You should instead listen once and define an onData method to perform the steps. See the documentation for .listen() here: https://api.dart.dev/stable/2.17.3/dart-async/Stream/listen.html
You could try wrapping the stdout streams in StreamIterator<String>. You will have to give it a try to verify, but I think this is what you are looking for.
Future<String> getOutAndAnswer(int testcase) async {
Process python = await Process.start('python', ['tasks/histogram/run.py']);
Process java = await Process.start('java', ['solutions/Histogram.java']);
String results = "";
StreamIterator<String> pythonIterator = StreamIterator(
python.stdout.transform(utf8.decoder).transform(LineSplitter()));
StreamIterator<String> javaIterator = StreamIterator(
java.stdout.transform(utf8.decoder).transform(LineSplitter()));
for (int i = 0; i < testcase; i++) {
if (await pythonIterator.moveNext()) {
final String out = pythonIterator.current;
if (out == 'EXIT') {
break;
}
java.stdin.writeln(out);
if (await javaIterator.moveNext()) {
final String answer = javaIterator.current;
python.stdin.writeln(answer);
results += "($out, $answer)";
}
}
}
await pythonIterator.cancel();
await javaIterator.cancel();
return results;
}
You may need to add the following imports:
import 'dart:async';
import 'dart:convert';
In Dart, stdin is a Stream<List<int>>. Bytes come in in chunks. What I want is a function that reads from stdin until I get some character (say '\0'), and then returns, so that future readers of stdin get the data after the '\0'.
Unfortunately because of the chunking, the '\0' byte might be in the middle of a chunk, so I kind of want to read a chunk, remove part of it, and then push it back to the start of the stream. But there isn't any way to do this.
Another option would be readByteSync() but reading bytes one at a time is going to be slow and this is in a GUI program so I can't use sync methods.
I think actually because a Stream<> can only ever be listened to once - even if a previous listener cancels its subscription - the only way is to have something permanently filtering the stream's events until the end of time. So you may as well just split the stream into two streams:
import 'dart:async';
class StdioPreambleSplitter {
StdioPreambleSplitter(this._input) {
var preambleFinished = false;
_input.listen((chunk) {
if (preambleFinished) {
_dataStream.add(chunk);
} else {
final nullByte = chunk.indexOf(0);
if (nullByte == -1) {
_dataStream.add(chunk);
} else {
preambleFinished = true;
_preambleStream.add(chunk.sublist(0, nullByte));
_dataStream.add(chunk.sublist(nullByte));
}
}
});
}
Stream<List<int>> preambleStream() {
return _preambleStream.stream;
}
Stream<List<int>> dataStream() {
return _dataStream.stream;
}
final Stream<List<int>> _input;
final StreamController<List<int>> _preambleStream = new StreamController();
final StreamController<List<int>> _dataStream = new StreamController();
}
Hopefully it doesn't add too much overhead.
Is there an easy way to open a file and continously read from it without the stream getting closed on EOF? Like the Unix command tail -f.
Just reading until EOF is described in the API docs. But I can't see an obvious/simple way to block or pause the stream for more input.
One solution would be to repeatedly reopen the file and continue reading from the last known length when I detect that the file size has changed.
Somethink like this
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...
}
You can also use Directory.watch to get notified about changes and then reopen and read from the last known position.
(even though this questions is a bunch of years old now, I stumbled across the same issue today and couldn't find a viable solution and therefore had to roll my own and wanted to share my findings with future generations of Dart programmers. ;-))
The dart:io package in conjunction with a bit of stream and async-await magic should offer everything that is needed to achieve a "tail -f"-like functionality:
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();
}
}
}
This function (tail) might then be used like that:
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);
});
}
I'm just new in this PCL libraries, I'm developing an iPhone app with Xamarin and I can't find the way to save it on the phone. The closest I get is with PCLStorage but he only saves text.
There is another way that I can save binary files with other procedure.
Thank you.
foreach (images element in json_object)
{
//var nameFile = Path.Combine (directoryname, element.name);
try{
IFile file = await folder_new.GetFileAsync(element.name);
}catch(FileNotFoundException ex ){
RestClient _Client = new RestClient(element.root);
RestRequest request_file = new RestRequest("/images/{FileName}");
request_file.AddParameter("FileName", element.name, ParameterType.UrlSegment);
_Client.ExecuteAsync<MemoryStream>(
request_file,
async Response =>
{
if (Response != null)
{
IFolder rootFolder_new = FileSystem.Current.LocalStorage;
IFile file_new = await rootFolder_new.CreateFileAsync(element.name,CreationCollisionOption.ReplaceExisting);
await file_new.WriteAllTextAsync(Response.Data);
}
});
}
}
Use the IFile.OpenAsync method to get a stream which you can use to read/write binary data. Here's how you would read a file:
IFile file = await folder_new.GetFileAsync(element.name);
using (Stream stream = await file.OpenAsync(FileAccess.Read))
{
// Read stream and process binary data from it...
}
How does one 'read' a file from a Dart program ?
http://api.dartlang.org/index.html
Dart would be running on the client-side and so taking files as input should be allowed.
You can find a usage of files in Dart's testing framework:
status_file_parser.dart (search for 'File').
In short:
File file = new File(path);
if (!file.existsSync()) <handle missing file>;
InputStream file_stream = file.openInputStream();
StringInputStream lines = new StringInputStream(file_stream);
lines.lineHandler = () {
String line;
while ((line = lines.readLine()) != null) {
...
};
lines.closeHandler = () {
...
};
Note that the API is not yet finalized and could change at any moment.
Edit: API has changed. See Introduction to new IO
Your question implies you want to do this from the client-side, that is, the browser. The dart:io library only works in the stand-alone VM on the command line.
If you do want to read a file from within the VM, there's now an easier way:
import 'dart:io';
main() {
var filename = new Options().script;
var file = new File(filename);
if (!file.existsSync()) {
print("File $filename does not exist");
return;
}
var contents = file.readAsStringSync();
print(contents);
}
If you do not want to block while the whole file is read, you can use the async version of readAsString which returns a Future:
file.readAsString().then((contents) {
print(contents);
});