How to fix undefined File() class and its methods in Dart? - dart

I want to save files in local storage of Android/iOS. I followed the Flutter cookbook to save files but it didn't work. There are examples everywhere using the File class, but it's undefined when I use it. I'm using Dart 2.2.0 and Flutter 1.2.1
I've tried example code snippets from a few websites. Nothing worked. File class, readAsString, and writeAsString are undefined in my Dart file.
Here's the code. Checked it in DartPad. Where am I wrong?
//packages
import 'dart:io';
import 'dart:async';
import 'package:path_provider/path_provider.dart';
//start
class File {
/// Directory Path
/// Local Directory Path
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
// For your reference print the AppDoc directory
print(directory.path);
return directory.path;
}
/// Reference for file Location
Future<File> get _localFile async {
final path = await _localPath;
final address = '$path/data.txt';
return File(address);
}
/// Presenting different Data as 1 String
String convertingtoString(String title, String author, String content) {
return '$title\n$author\n\n$content';
}
/// Write to file
/// Writing as String
Future<File> writeContent(String matter) async {
/// Get matter converted to string as matter
final file = await _localFile;
// Write the file
return file.writeAsString(matter);
}
/// Read from file
Future<String> readcontent() async {
try {
final file = await _localFile;
// Read the file
String contents = await file.readAsString();
return contents;
} catch (e) {
// If there is an error reading, return a default String
return 'Error, Couldn\'t read file';
}
}
}
This is code from my android flutter project. I get the same errors like DartPad in VScode

You've created your own class named File, so that hides the File class from dart:io. Name your custom class something else, or do:
import 'dart:io' as io;
and use io.File where you intend to use dart:io's File class. (I recommend renaming your custom class to avoid confusion.)
Original answer
Since you have import 'dart:io';, the File class should be available to you.
If you're trying this solely with DartPad, then it (among other things) won't work there because dart:io is meant to be used with a Dart VM. dart:io won't work in a browser, which has a sandboxed environment and generally prevents filesystem access:
Important: Browser-based applications can't use this library. Only servers, command-line scripts, and Flutter mobile apps can import and use dart:io.

Related

Using Futures to load config.json in Flutter

Being new to Dart/Flutter I am using this snippet to try and load a config.json file that I have stored in my assets folder. In trying to read this file, I am using models on the Dart language Futures documentation and in the Flutter docs on reading local text files:
import 'dart:async' show Future;
import 'package:flutter/services.dart' show rootBundle;
import 'dart:convert';
Future<List> loadAsset() async {
String raw = await rootBundle.loadString('assets/config.json');
List configData = json.decode(raw);
return configData;
}
Then, inside my class, I try to load the config into a List, like this:
Future<List> configData = loadAsset();
print(configData.toString());
// prints out: Instance of 'Future<List<dynamic>>'
The result of all this seems to work. Yet I can find no way of using the data I have loaded. Any effort to access elements in the List, e.g. configData[0] results in an error:
The following _CompileTimeError was thrown building
HomePage(dirty, state: HomePageState#b1af8):
'package:myapp/pages/home_page.dart': error:
line 64 pos 19: lib/pages/home_page.dart:64:19:
Error: The method '[]' isn't defined for the class
'dart.async::Future<dart.core::List<dynamic>>'.
Try correcting the name to the name of an existing method,
or defining a method named '[]'.
I would like to convert the configData Future into a normal object that I can read and pass around my app. I am able to do something very similar, and to get it to work inside a widget's build method, using a FutureBuilder and the DefaultAssetBundle thus...
DefaultAssetBundle
.of(context)
.loadString('assets/config.json')
...but I don't want the overhead of reloading the data inside all the widgets that need it. I would like to load inside a separate Dart package and have it available as a global configuration across all my app. Any pointers would be appreciated.
I have tried the suggestion by RĂ©mi Rousselet:
List configData = await loadAsset();
print(configData[0]);
In this case, I get a compiler error:
compiler message: lib/pages/home_page.dart:55:21: Error: Getter not found: 'await'.
compiler message: List configData = await loadAsset();
compiler message: ^^^^^
You can't do configData[0] as configData is not a List but a Future.
Instead, await the future to have access to the List inside
List configData = await loadAsset();
print(configData[0]);
You can only use await INSIDE async methods.
If you want to you your assets in entire application you want to load the asset in the main method similar like this.
void main() async {
StorageUtils.localStorage = await SharedPreferences.getInstance();
}
Now you can use localStorage synchronously in entire application and you don't need to deal with another asynchronous calls or load it again.
Different example, same principle.

Returning anonymous JS function which returns javascript plain object from Dart

Dart Code
import 'dart:html' as html;
import 'dart:js' as js;
import 'package:js/js.dart';
void main() {
var data = new AddLocationData(locationName: "Location1", locationPath: "ThisFolder");
var func = () => data;
html.window.console.log(func);
html.window.console.log(func());
}
#JS("")
#anonymous
class AddLocationData {
external String get locationName;
external String get locationPath;
external factory AddLocationData({String locationName, String locationPath});
}
You would assume that func will be a js function but its not. Its type/name is main_closure. See the screenshot
So the first two lines were printed from Dart code then I used Chrome Inspect Element window and right clicked on main_closure' and selected "Store as global variable" which then printedtemp1` and then I used it to display some information about the generated code.
So it is clear Dart returned an object and not a js function and so is the reason of asking this question.
So I want temp1 to be a function instead of temp1.call$0 so that I can get the data by calling temp1() and not temp1.call$0().
See js package doc:
Passing functions to JavaScript.
If you are passing a Dart function to a JavaScript API, you must wrap it using allowInterop or allowInteropCaptureThis.

How to read file from an imported library

I have two packages: webserver and utils which provides assets to webserver.
The webserver needs access to static files inside utils. So I have this setup:
utils/
lib/
static.html
How can I access the static.html file in one of my dart scripts in webserver?
EDIT: What I tried so far, is to use mirrors to get the path of the library, and read it from there. The problem with that approach is, that if utils is included with package:, the url returned by currentMirrorSystem().findLibrary(#utils).uri is a package uri, that can't be transformed to an actual file entity.
Use the Resource class, a new class in Dart SDK 1.12.
Usage example:
var resource = new Resource('package:myapp/myfile.txt');
var contents = await resource.loadAsString();
print(contents);
This works on the VM, as of 1.12.
However, this doesn't directly address your need to get to the actual File entity, from a package: URI. Given the Resource class today, you'd have to route the bytes from loadAsString() into the HTTP server's Response object.
I tend to use Platform.script or mirrors to find the main package top folder (i.e. where pubspec.yaml is present) and find imported packages exported assets. I agree this is not a perfect solution but it works
import 'dart:io';
import 'package:path/path.dart';
String getProjectTopPath(String resolverPath) {
String dirPath = normalize(absolute(resolverPath));
while (true) {
// Find the project root path
if (new File(join(dirPath, "pubspec.yaml")).existsSync()) {
return dirPath;
}
String newDirPath = dirname(dirPath);
if (newDirPath == dirPath) {
throw new Exception("No project found for path '$resolverPath");
}
dirPath = newDirPath;
}
}
String getPackagesPath(String resolverPath) {
return join(getProjectTopPath(resolverPath), 'packages');
}
class _TestUtils {}
main(List<String> arguments) {
// User Platform.script - does not work in unit test
String currentScriptPath = Platform.script.toFilePath();
String packagesPath = getPackagesPath(currentScriptPath);
// Get your file using the package name and its relative path from the lib folder
String filePath = join(packagesPath, "utils", "static.html");
print(filePath);
// use mirror to find this file path
String thisFilePath = (reflectClass(_TestUtils).owner as LibraryMirror).uri.toString();
packagesPath = getPackagesPath(thisFilePath);
filePath = join(packagesPath, "utils", "static.html");
print(filePath);
}
To note that since recently Platform.script is not reliable in unit test when using the new test package so you might use the mirror tricks that I propose above and explained here: https://github.com/dart-lang/test/issues/110

Code cannot find a line on a website

I've been trying to find a line and print it out on this website: http://www.easports.com/player-hub/360/Its+McDoom
Right now it prints out everything on the website, but I cannot find the line I am looking for. I am trying to print out "H2h Skill Points: 1053", but I cannot find anything like that in the console.
I only really want it to print that 1 line, not the whole thing, but I can't even find it.
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
public class ElectronicArtsStatHub {
/**
* #param args
*/
public static void main (String[] args) throws Exception{
URL oracle = new URL("http://www.easports.com/player-hub/360/Its+McDoom");
URLConnection yc = oracle.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(
yc.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
System.out.println(inputLine);
}
in.close();
}
}
The first problem is that the information your trying to find isn't actually in the data you are currently outputting.
When you open the page in your browser you get the main page elements but then your browser then runs some Javascript code which presumably uses AJAX to get the stats and fill in the table.
The URLConnection receives the same data that your browser initially does and does not execute the Javascript so if you check your output that data your looking for isn't actually there at all.
Possible solutions include finding a different source for this data or executing the Javascript in Java possibly by using HTMLUnit
There may be some helpful infomation on this related question

How do I list the contents of a directory with Dart?

I would like to list all the contents of a directory (on the file system) using Dart. How can I do this?
How to list the contents of a directory in Dart
final dir = Directory('path/to/directory');
final List<FileSystemEntity> entities = await dir.list().toList();
This creates a Directory from a path. Then it converts it to a list of FileSystemEntity, which can be a File, a Directory, or a Link. By default subdirectories are not listed recursively.
If you want to print that list, then add this line:
entities.forEach(print);
If you want to only get the files then you could do it like so:
final Iterable<File> files = entities.whereType<File>();
The API has changed and I have updated the async code for M4 release (0.5.16_r23799 ):
Future<List<FileSystemEntity>> dirContents(Directory dir) {
var files = <FileSystemEntity>[];
var completer = Completer<List<FileSystemEntity>>();
var lister = dir.list(recursive: false);
lister.listen (
(file) => files.add(file),
// should also register onError
onDone: () => completer.complete(files)
);
return completer.future;
}
The list method returns a Stream where each emitted event is a directory entry:
Directory dir = Directory('.');
// execute an action on each entry
dir.list(recursive: false).forEach((f) {
print(f);
});
As the name suggest, listSync method is the blocking version:
// create a list of entries
List<FileSystemEntity> entries = dir.listSync(recursive: false).toList();
What method to use depends on application context. A note directly from the docs:
Unless you have a specific reason for using the synchronous version of a method, prefer the asynchronous version to avoid blocking your program.
This answer is out of date. Please see the accepted answer.
There are two ways to list the contents of a directory using the Dart VM and the dart:io library.
(note: the following only works in the Dart VM when running on the command-line or as a server-side app. This does not work in a browser or when compiled to JavaScript.)
Setup
First, you need to import the dart:io library. This library contains the classes required to access files, directories, and more.
import 'dart:io';
Second, create a new instance of the Directory class.
var dir = new Directory('path/to/my/dir');
Listing contents in a script
The easiest way is to use the new listSync method. This returns a List of contents. By default this does not recurse.
List contents = dir.listSync();
for (var fileOrDir in contents) {
if (fileOrDir is File) {
print(fileOrDir.name);
} else if (fileOrDir is Directory) {
print(fileOrDir.path);
}
}
If you want to recurse through directories, you can use the optional parameter recursive.
List allContents = dir.listSync(recursive: true);
WARNING if your directory structure has circular symlinks, the above code will crash because it's following symlinks recursively.
This method, using listSync, is especially useful when you are writing a shell script, command-line utility, or similar app or script with Dart.
Listing contents in a server
A second way to list the contents of a directory is to use the async version of list. You would use this second method when you need to list a directory in response to, say, an HTTP request. Remember that each of Dart's isolates runs in a single thread. Any long running process can block the event loop. When interactivity is important, or serving lots of clients from a single Dart script, use the async version.
With the async version, dir.list() returns a DirectoryLister. You can register three different callbacks on DirectoryLister:
onFile: called when a file or directory is encountered
onDone: called when the directory lister is done listing contents
onError: called when the lister encounters some error
Here is a simple function that returns a Future of a list of strings, containing file names in a directory:
Future<List<String>> dirContents(Directory dir) {
var filenames = <String>[];
var completer = new Completer();
var lister = dir.list();
lister.onFile = (filename) => filenames.add(filename);
// should also register onError
lister.onDone = (_) => completer.complete(filenames);
return completer.future;
}
Of course, this method is perfect for servers, it's more cumbersome for simple scripts.
Luckily, Dart supports both methods for you to use!
Inside and asynchronous function write this
List<FileSystemEntity> allContents = await Directory("folder/path").list().toList();
Now you have a list with all of the contents
Here is my version using async/await, returning a List of Files only:
List<File> filesInDirectory(Directory dir) async {
List<File> files = <File>[];
await for (FileSystemEntity entity in dir.list(recursive: false, followLinks: false)) {
FileSystemEntityType type = await FileSystemEntity.type(entity.path);
if (type == FileSystemEntityType.FILE) {
files.add(entity);
print(entity.path);
}
}
return files;
}
With this function you can print all the directories and files of a directory.
You just need to pass a specific path.
Future listDir(String folderPath) async {
var directory = new Directory(folderPath);
print(directory);
var exists = await directory.exists();
if (exists) {
print("exits");
directory
.list(recursive: true, followLinks: false)
.listen((FileSystemEntity entity) {
print(entity.path);
});
}
}
To get a list of file names with a certain string, you can use this code:
String directory = (await getApplicationDocumentsDirectory()).path;
List<FileSystemEntity> files = Directory(directory).listSync(recursive: false);
List<String> filePaths = [];
for (var fileSystemEntity in files) {
if (basename(fileSystemEntity.path).contains('mystring')) {
filePaths.add(fileSystemEntity.path);
}
}
You can use the basename function if you need just the file name, and not the whole path.
To get all files with given extension:
import 'package:path/path.dart' as p;
Future<List<File>> getAllFilesWithExtension(String path, String extension) async {
final List<FileSystemEntity> entities = await Directory(path).list().toList();
return entities.whereType<File>().where((element) => p.extension(element.path) == extension).toList();
}

Resources