Search code examples
dart

Issue converting FileEntities from Directory.list() to strings


If I have a script like this

import 'package:path/path.dart' as p;
import 'dart:io';
import 'dart:async';

void main() async {
  final inDir = p.join(Directory.current.path, 'tmp', 'in'); // should we rename this
  var dir = Directory(inDir);
  final List<FileSystemEntity> fileList = await dir.list().toList();
  for (var file in fileList.where((entity) => entity is File) ) {
    print ("Processing ${(file as File).toString()}");
    final contents = (file as File).readAsStringSync();
    print (contents);
  }
}

it works fine.

Processing File: 'C:\FlutterProjects\project\tmp\a.txt'
some text

However if I want to get the file path to pass to another function as a string

import 'package:path/path.dart' as p;
import 'dart:io';
import 'dart:async';

void main() async {
  final inDir = p.join(Directory.current.path, 'tmp'); // should we rename this
  var dir = Directory(inDir);
  final List<FileSystemEntity> fileList = await dir.list().toList();
  for (var file in fileList.where((entity) => entity is File) ) {
    print ("Processing ${(file as File).toString()}");
    readFile ((file as File).toString());
  }
}

void readFile (String filePath) {

    final file = File(filePath); 
    final contents = file.readAsStringSync();
    print (contents);

}

... then it doesn't work...

Processing File: 'C:\FlutterProjects\project\tmp\a.txt'
Unhandled exception:
FileSystemException: Cannot open file, path = 'File: 'C:\FlutterProjects\project\tmp\a.txt'' (OS Error: The filename, directory name, or volume label syntax is incorrect.
, errno = 123)
#0      _File.throwIfError (dart:io/file_impl.dart:675:7)
#1      _File.openSync (dart:io/file_impl.dart:490:5)
#2      _File.readAsBytesSync (dart:io/file_impl.dart:574:18)
#3      _File.readAsStringSync (dart:io/file_impl.dart:624:18)
#4      readFile (file:///C:/FlutterProjects/project/bin/parse-files.dart:18:27)
#5      main (file:///C:/FlutterProjects/project/bin/parse-files.dart:11:5)
<asynchronous suspension>

I am guessing because it still has File: at the beginning. So I could treat that as an entity in the function itself or I transform the string to not have File: a the beginning but I don't understand why it is not sending the string of the file as a file (which is what I would like to do keep the function more reusable).

TL;DR why doesn't ((file as File).toString()); do what I expect when file is a FileEntity.


Solution

  • The output of calling toString() on a File object are not a path you can use for something. If you see your code, the result of calling toString() on your File are actually the String:

    File: 'C:\FlutterProjects\project\tmp\a.txt'
    

    So what you are actually ended up doing, are calling:

    File("File: 'C:\FlutterProjects\project\tmp\a.txt'");
    

    Which fails since that is not a valid path and not something you can read from.

    Instead of calling toString(), you should use the .path property on the File object. Or just send the File as argument to your method:

    import 'package:path/path.dart' as p;
    import 'dart:io';
    
    void main() async {
      final inDir = p.join(Directory.current.path, 'tmp'); // should we rename this
      var dir = Directory(inDir);
      final List<FileSystemEntity> fileList = await dir.list().toList();
      
      for (var file in fileList.whereType<File>()) {
        print("Processing ${file.path}");
        readFile(file);
      }
    }
    
    void readFile(File file) {
      final contents = file.readAsStringSync();
      print(contents);
    }
    

    Also, I have fixed your unneeded casting of file types in this code. If you use whereType, it actually filter based on type checking and returns the right type of objects.