0

I am trying to add the content of directory using this approach and asign it to List but not sure why it's not working. I see it's async problem but not sure how to solve it.I expect to return the list of files from retCont() but instead it's returning empty list.

import 'dart:io';

void main() async {
  print('CONT: ${await retCont()}');
}

Future retCont() async {
  var myDir = Directory.current;
  List cont = [];
  await myDir.list().listen((FileSystemEntity entity) {
    print(entity.path);
    cont.add(entity.path);
  });
  return cont;
}
verb
  • 69
  • 5
  • Check this out: https://stackoverflow.com/a/17081903/5362583 – Alok Aug 02 '20 at 09:44
  • Does this answer your question? [How do I list the contents of a directory with Dart?](https://stackoverflow.com/questions/14268967/how-do-i-list-the-contents-of-a-directory-with-dart) – Alok Aug 02 '20 at 09:45

1 Answers1

1

listen() returns a StreamSubscription<FileSystemEntity> which is not a Future so you cannot await on that.

The list() call returns Stream<FileSystemEntity>. For streams you can instead of await and listen() use await for like this:

import 'dart:io';

Future<void> main() async {
  print('CONT: ${await retCont()}');
}

Future<List<String>> retCont() async {
  final myDir = Directory.current;
  final cont = <String>[];
  
  await for (final entity in myDir.list()) {
    print(entity.path);
    cont.add(entity.path);
  }
  
  return cont;
}

And as a bonus fact, the same program can be written like this if you skip the print(entity.path);.

import 'dart:io';

Future<void> main() async {
  print('CONT: ${await retCont()}');
}

Future<List<String>> retCont() =>
    Directory.current.list().map((event) => event.path).toList();

If you really want to use StreamSubscription I think the easiest way is to use a Completer instance which you can complete when you have got all the elements from List():

import 'dart:async';
import 'dart:io';

Future<void> main() async {
  print('CONT: ${await retCont()}');
}

Future<List<String>> retCont() {
  final myDir = Directory.current;
  final cont = <String>[];
  final completer = Completer<List<String>>();

  myDir.list().listen((FileSystemEntity entity) {
    print(entity.path);
    cont.add(entity.path);
  }, onDone: () => completer.complete(cont));

  return completer.future;
}
julemand101
  • 28,470
  • 5
  • 52
  • 48
  • 2
    If you are adding all the data of a stream into a list imo in this case it's just better to use: `var list = await myDir.list().toList();` – Mattia Aug 02 '20 at 09:58
  • @julemand101 thank you for your answer . Can we achieve the same result using StreamSubscription ??? If so could you provide any example please – verb Aug 02 '20 at 10:52
  • Added example of using `StreamSubscription`. – julemand101 Aug 02 '20 at 11:02
  • 1
    If you don't use the `StreamSubscription`, you should most likely not use `listen` at all, but use `forEach` instead. In this case: `return myDir.list().forEach((entity) { cont.add(entity.path); }).then((_) => cont);` -- no completer needed. Or maybe `return myDir.list().fold>([], (list, entity) => list..add(entity.path));`. – lrn Aug 02 '20 at 20:47