How to change file date attributes (at least modified date) using "dart:io"? - dart-io

I want change the modificitation date and time of the file.
How I can do this in Dart platform?
Example from the .NET Framework, C# language.
File.SetLastWriteTime(path, DateTime.Now);
I'm sure it's possible.
I just don't know how to do it in standard way in such a wonderful platform as the Dart.
It is impossible in Dart

The first method that comes to mind would be to just call touch using Process.
eg.
import 'dart:io';
Future touchFile(File f) {
return Process.run("touch", [f.path]);
}
void main() {
var f = new File('example');
print(f.statSync().changed);
touchFile(f).then((_) {
print(f.statSync().changed);
});
}
The equivalent code for people who are chained to windows would be
Future touchFile(File f) {
return Process.run("copy", ["\b", f.path, "+,,"]);
}
See this question

Calling out to system processes seems like a serious hack. Here are two functions that uses only Dart APIs, and is not platform dependent. One is synchronous, and the other asynchronous. Use whichever version suits your needs.
void touchFileSync(File file) {
final touchfile = file.openSync(mode: FileMode.append);
touchfile.flushSync();
touchfile.closeSync();
}
Future<void> touchFile(File file) async {
final touchfile = await file.open(mode: FileMode.append);
await touchfile.flush();
await touchfile.close();
}
This will update the last modified time.

Related

How does Dart treat cascading Futures?

Say I have this class:
void main() async {
final example = ExampleClass();
await example.waitOne();
await example.waitOne();
print('finished');
}
class ExampleClass {
Future<void> waitOne() async {
await Future.delayed(Duration(seconds: 1));
print('1 second');
}
}
This code works exactly as I expect it to. It's output is as follows:
1 second
1 second
finished
Then we have this code:
void main() async {
final example = ExampleClass();
await example
..waitOne()
..waitOne();
print('finished');
}
This code now has cascading operators (..) and the output seems strange:
finished
1 second
1 second
The code skips the two futures and prints "finished" to the console first, then "1 second" gets printed twice at the same time (like Future#wait would do).
Why does Dart act in this way?
In your example with the cascading operator adding await doesn't do anything since the cascade operation doesn't return anything hence there is no future to be awaited and then finished is printed right away
Remember that the result of the cascade operator is the original object that you used it on. That is, for var result = object..x()..y()..z(), result will be assigned the value of object, regardless of what x, y, or z return. The values returned by x(), y(), and z() are ignored. It's the equivalent of:
object.x();
object.y();
object.z();
var result = object;
Your case, which involves Futures, is no different:
final example = ExampleClass();
await example
..waitOne()
..waitOne();
So you're doing the equivalent of:
final example = ExampleClass();
example.waitOne(); // The returned Future is ignored.
example.waitOne(); // The returned Future is ignored.
await example; // Incorrectly using await on a non-Future.
(Note that enabling the unawaited_futures and await_only_futures lints would catch this mistake.)
To properly wait, you can't use the cascade operator and will need to explicitly await the individual operations. Also see the issue Prefix await is cumbersome to work with. which discusses possible changes to the language to support using await with member or cascade operators.

How to get my object (Generator) from a Map<UUID, List<Generator>> with streams?

I've been wanting to check the location of my Generator and use streams to check if the location is valid.
The idea was as follows;
public Generator getGeneratorFromLocation(final Location location) {
for (List<Generator> generator : playerGeneratorMap.values()) {
for (Generator generator1 : generator) {
if (generator1.getGenLocation().equals(location)) {
return generator1;
}
}
}
return null;
}
I'm wanting to return a Generator from this using streams instead to try and learn more ways of doing it.
Current map:
public final Map<UUID, List<Generator>> playerGeneratorMap = new HashMap<>();
Any help would be greatly appreciated.
You can use AtomicRef object to init a retVal and then assign the wanted Generator to it in the lambda expression because regular vars can't be assigned in lambdas, only final or effectivly final can be used inside arrow functions.
This function should solve the problem :)
public Generator getGeneratorFromLocation(final Location location) {
AtomicReference<Generator> retVal = new AtomicReference<>(null);
playerGeneratorMap.values().stream().forEach(generators -> {
generators.forEach(generator -> {
if (generator.getLocation().equals(location)) {
retVal.set(generator);
}
});
});
return retVal.get();
}
By the way, streams are unnecessary because you have Collection.forEach instead of Stream.forEach, streams are used for more 'exotic' types of iterations like, filter, anyMatch, allMatch, reduce and such functionalities, you can read about Streams API on Oracle's website,
I'll link in the docs for you for future usage, important for functional proggraming.

How to know if a certain future is complete by avoiding a chain of future as return types?

Scenario
If I want to read from a file and store the data in a Map, and if that map is being used multiple times for validation.
Is it possible for me to do this without having to change the return type of all methods, that use the above mentioned map, to Future?
Example:
Map metadata = null
Future readFromFile async {
.... metadata = await File.readingfromFile(...);
}
Future getRegion(..) async {
if(metadata == null) { await readFromFile() }
return metadata["region"]
}
Using the above code if a method(like isValidRegion,etc) that uses and needs getRegion(..) to complete, then the return type of isValidRegion should be converted to Future.
Future<bool> isValidRegion(..) async {
return ((await getRegionData(...)) != null )
}
If that isValidRegion is present within another methods, then the return type of them have to be changed to Future as well.
Future<String> parse(...) async {
....
if(await isValidRegion()) {
...
}
...
}
What is an elegant way to avoid this chain of futures as return types?
Async execution is contagious, there is nothing you can do to get back from async to sync execution.
What you can do is to do the read from the file synchronous to avoid the problem in the first place (if this is possible, if you read it from a network connection, this might not be possible).

How do I change my simple asynchronous Dart function to use the new async keyword?

I have a Dart function that looks like:
Future beAwesome() {
if (notActuallySupported) {
return new Future.error(new UnsupportedError('uh oh'));
}
return new Future.value(42);
}
// ...
beAwesome().then((answer) => print(answer));
I want to use the new async/await functionality. How do I change my function?
In general, add the word async after your function's signature and before the {. Also, return raw values instead of wrapping those values in futures. Also, throw actual exceptions instead of wrapping the errors with a future.
Here's the new version:
Future beAwesome() async {
if (notActuallySupported) {
throw new UnsupportedError('uh oh');
}
return 42;
}
// ...
var answer = await beAwesome();
print(answer);
Note that you should still use Future as the return-type annotation.

Check if Future is complete

Before 'm3' you could check if a Future was completed with 'completer.future.isComplete' this seems to be gone. Is there a replacement? or do I need to save it myself then
(it seems inside the _CompleterImpl there is still a field '_isComplete' but its not exposed
With M3 Dart, it's best to just use your own flag.
future.whenComplete(() {
tweenCompleted = true;
});
Dart is a single threaded language so there is no race condition here.
Note that the [action] function is called when this future completes, whether it does so with a value or with an error.
An alternative to #Cutch's solution is to wrap the Future in a Completer:
Completer<T> wrapInCompleter<T>(Future<T> future) {
final completer = Completer<T>();
future.then(completer.complete).catchError(completer.completeError);
return completer;
}
Future<void> main() async {
final completer = wrapInCompleter(asyncComputation());
if (completer.isCompleted) {
final result = await completer.future;
// do your stuff
}
}
This approach is more resourceful since you can both await for the completion asynchronously and check whether the future is completed synchronously.
Using an extension on Future and building on Hugo Passos' answer:
extension FutureExtension<T> on Future<T> {
/// Checks if the future has returned a value, using a Completer.
bool isCompleted() {
final completer = Completer<T>();
then(completer.complete).catchError(completer.completeError);
return completer.isCompleted;
}
}

Resources