How to read and write a text file in Flutter - dart

How do you read text from a file and write text to a file?
I've been learning about how to read and write text to and from a file. I found another question about reading from assets, but that is not the same. I will add my answer below from what I learned from the documentation.

Setup
Add the following plugin in pubspec.yaml:
dependencies:
path_provider: ^1.6.27
Update the version number to whatever is current.
And import it in your code.
import 'package:path_provider/path_provider.dart';
You also have to import dart:io to use the File class.
import 'dart:io';
Writing to a text file
_write(String text) async {
final Directory directory = await getApplicationDocumentsDirectory();
final File file = File('${directory.path}/my_file.txt');
await file.writeAsString(text);
}
Reading from a text file
Future<String> _read() async {
String text;
try {
final Directory directory = await getApplicationDocumentsDirectory();
final File file = File('${directory.path}/my_file.txt');
text = await file.readAsString();
} catch (e) {
print("Couldn't read file");
}
return text;
}
Notes
You can also get the path string with join(directory.path, 'my_file.txt') but you need to import 'package:path/path.dart'.
Flutter's Official Documentation of Reading and Writing Files
This works for iOS, Android, Linux and MacOS but not for web.

As additional info to #Suragch's answer, if you want to find the file you created, you can do as the images show:
And then inside that data folder, go again to a folder named data and search for your package, and then go to:
If you happen to create new files, in order to be able to see them, just right click and click Synchronize.

An another way to pull the file from the device is by using adb pull command. You can find the file path by debugging the code and then use adb pull command. adb is located in Android SDK -> platform-tools directory.
./adb pull /storage/emulated/0/Android/data/com.innovate.storage.storage_sample/files/sample.txt ~/Downloads

#Suragch 's answer is right. Except the version of path_provider that you want to use now is:
path_provider: ^2.0.9

Related

How to get the (absolute) path to the Download folder?

In a Flutter project, how to get the (absolute) path to the Download folder in my Android device?
My Download folder is next those one: Alarms, Android, data, DCIM, Documents, Movies, Music, Notifications, Pictures, ...
Device: GALAXY S8+ SM-G955F. Android 8.0. Not Rooted. Flutter beta v0.5.1. Dart 2.0.0-dev.58.0. Windows 10
File manager showing my Download folder
Using this package path_provider I got those 3 paths:
/data/user/0/com.exemple.fonzo/cache
/data/user/0/com.exemple.fonzo/app_flutter
/storage/emulated/0
I cannot find or access those 3 folders from Solid-Explorer file manager on my un-rooted device GALAXY S8+ SM-G955F. Android 8.0. I just want to find the absolute path to a folder (like Download) that:
I can access with my Android file manager app.
I can write files in this folder from my flutter project.
I personaly use this method :
path_provider: 2.0.9
Future<String?> getDownloadPath() async {
Directory? directory;
try {
if (Platform.isIOS) {
directory = await getApplicationDocumentsDirectory();
} else {
directory = Directory('/storage/emulated/0/Download');
// Put file in global download folder, if for an unknown reason it didn't exist, we fallback
// ignore: avoid_slow_async_io
if (!await directory.exists()) directory = await getExternalStorageDirectory();
}
} catch (err, stack) {
print("Cannot get download folder path");
}
return directory?.path;
}
Output :
On IOS it create a folder with the name of your app and put the file inside it. Users can easily find the folder, it's intuitive.
On Android, I test if the default download folder exist (it work most of the time), else I put inside the external storage directory (in this case, it's hard for the user to manually find the file...).
For IOS : (Mentioned by #Wai Yan)
Maybe add the follwing key in your plist.info to better see your app in document folder (https://stackoverflow.com/a/74457977/10088439).
UISupportsDocumentBrowser
I used this library to get public download directory in Android
ext_storage
import 'package:ext_storage/ext_storage.dart';
Future<String> _getPathToDownload() async {
return ExtStorage.getExternalStoragePublicDirectory(
ExtStorage.DIRECTORY_DOWNLOADS);
}
final String path = await _getPathToDownload();
print(path);
You could use the downloads_path_provider package. You will have add <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> to your AndroidManifest.xml. Also if you plan to write into that folder and want your application to work for android version > 6 you must ask the user for writing permission. You could do that with https://pub.dev/packages/permission_handler.
await PermissionHandler().requestPermissions([PermissionGroup.storage]);
Change the function getApplicationDocumentsDirectory() to getExternalStorageDirectory() it should show the external directory for the app.
You should use native feature.
At time, to access phone directory is provided by path_provider package .
With it, you can acceess: temporary directory, app directory, external storage.
Doc: https://pub.dartlang.org/packages/path_provider
In Flutter
https://pub.dev/packages/ext_storage
Installation
Add ext_storage as a dipendency in your project pubspeck.yaml.
dependencies:
ext_storage:
Usage
First, you write import ext_storage package.
import 'package:ext_storage/ext_storage.dart';
void dirpath() async {
var path = await ExtStorage.getExternalStoragePublicDirectory(ExtStorage.DIRECTORY_DOWNLOADS);
}
I simplified it without plugins
I used this code and it's working like a charm
Directory dir = Directory('/storage/emulated/0/Download');
Using path provider package, you should be able to do this:
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as p;
String? downloadDirectory;
if (Platform.isAndroid) {
final externalStorageFolder = await getExternalStorageDirectory();
if (externalStorageFolder != null) {
downloadDirectory = p.join(externalStorageFolder.path, "Downloads");
}
} else {
final downloadFolder = await getDownloadsDirectory();
if (downloadFolder != null) {
downloadDirectory = downloadFolder.path;
}
}

How to add a File Picker plugin in Flutter?

I am creating a Flutter project in which, I have a piece of data (JSON) that I want to Import from and Export to a location the user wants to. In order to achieve this, I require a File Picker plugin in Flutter. Now, I searched the Dart Packages repository for "file picker" but didn't find one.
Is there a way to get a File Picker that looks like this:
or even this...
The first screenshot is preferable for me as it allows file selection from different sources (like Drive).
Also, since I want to Export the data, I might want a Folder Picker too. ;)
But, if there is any other alternative to Folder Picker. I'd be happy to know...
I've created a file_picker plugin some time ago in order to make it possible to pick (both on iOS and Android) absolute paths and then loaded it with Flutter.
You can check it here: https://pub.dev/packages/file_picker
I used file_picker library to pick files. you can use this for pick images as well.
Future getPdfAndUpload(int position) async {
File file = await FilePicker.getFile(
type: FileType.custom,
allowedExtensions: ['pdf','docx'], //here you can add any of extention what you need to pick
);
if(file != null) {
setState(() {
file1 = file; //file1 is a global variable which i created
});
}
}
here file_picker flutter library.
I'm in the exact same boat as you, haha!
I noticed documents_picker 0.0.2. It allows the user to pick multiple files, and it seems to fit the need!
check it out: https://pub.dartlang.org/packages/documents_picker#-readme-tab-
Here's a better document picker. It looks like the native document picker from the Storage Access Framework, which is what you have in your picture.
flutter_document_picker
Just found the FileSelector plugin from flutter.dev. Compatible with MacOS, Windows and Web.
From its pub.dev page:
Open a single file
final typeGroup = XTypeGroup(label: 'images', extensions: ['jpg', 'png']);
final file = await openFile(acceptedTypeGroups: [typeGroup]);
Open multiple files at once
final typeGroup = XTypeGroup(label: 'images', extensions: ['jpg', 'png']);
final files = await openFiles(acceptedTypeGroups: [typeGroup]);
Saving a file
final path = await getSavePath();
final name = "hello_file_selector.txt";
final data = Uint8List.fromList("Hello World!".codeUnits);
final mimeType = "text/plain";
final file = XFile.fromData(data, name: name, mimeType: mimeType);
await file.saveTo(path);
MacOS: Provide file read or/and write privileges
On target MacOS please provide sufficient rights using Xcode:
In case you don't provide file read or/and write permissions, the call to
final XFile? file =
await openFile(acceptedTypeGroups: <XTypeGroup>[typeGroup]);
neither shows anything not returns.

Processing and API's

Here's the top chunk of the code:
import java.util.* ;
//Build an ArrayList to hold all of the words that we get from the imported tweets
ArrayList<String> words = new ArrayList();
void setup() {
//Set the size of the stage, and the background to black.
size(800,800);
background(0);
smooth();
frameRate(5);
//Credentials
ConfigurationBuilder cb = new ConfigurationBuilder();
I'm trying to do something similar to Jer Thorp's tutorial: http://blog.blprnt.com/blog/blprnt/quick-tutorial-twitter-processing
I keep getting an error though: Cannot find a class or type named "ConfigurationBuilder"
I've tried to import stuff and keep getting errors when I try to drag and drop files- any suggestions?
You should be able to just drag the library .jar file onto the Processing editor. Make sure you get the correct .jar file, which you can check by either examining it as an archive file, or using the jar tf command.
You could also import the library using the Sketch -> Import Library menu. If the library isn't already installed, then you'll have to manually install it using the steps outlined here: http://wiki.processing.org/w/How_to_Install_a_Contributed_Library

Access to pubspec.yaml attributes (version) from Dart app

Is there any way to access some of the attributes listed in a pubspec.yaml file in that files Dart application?
In particular, the version and description attributes may be quite useful to see in a version info dialog, or even a '--version' when using a console app. I haven't been able to find a way to access in the API. I'm not sure if Mirrors would have anything appropriate, but if a web app is compiled to JS, then I don't see the description anywhere in the output JS.
Thanks.
EDIT
feature request: https://code.google.com/p/dart/issues/detail?id=18769
FOR FLUTTER ONLY
Please use this new package package_info_plus from flutter community.
import 'package:package_info_plus/package_info_plus.dart';
PackageInfo packageInfo = await PackageInfo.fromPlatform();
String appName = packageInfo.appName;
String packageName = packageInfo.packageName;
String version = packageInfo.version;
String buildNumber = packageInfo.buildNumber;
BELOW SOLUTION IS DEPRICATED.
I know the OP wants to read YAML but for flutter dev's you guys can read the version and other info of the application using package_info.
This is the sample to fetch details from Android/iOS application.
import 'package:package_info/package_info.dart';
PackageInfo packageInfo = await PackageInfo.fromPlatform();
String appName = packageInfo.appName;
String packageName = packageInfo.packageName;
String version = packageInfo.version;
String buildNumber = packageInfo.buildNumber;
you can install the "dart_config" package and use this code to parse a pubspec.yaml file:
import 'package:dart_config/default_server.dart';
import 'dart:async';
void main() {
Future<Map> conf = loadConfig("../pubspec.yaml");
conf.then((Map config) {
print(config['name']);
print(config['description']);
print(config['version']);
print(config['author']);
print(config['homepage']);
print(config['dependencies']);
});
}
The output looks similar to this:
test_cli
A sample command-line application
0.0.1
Robert Hartung
URL
{dart_config: any}
EDIT
You can do it with the Yaml package itself:
*NOTE: this will not work on Flutter Web
import 'package:yaml/yaml.dart';
import 'dart:io'; // *** NOTE *** This will not work on Flutter Web
void main() {
File f = new File("../pubspec.yaml");
f.readAsString().then((String text) {
Map yaml = loadYaml(text);
print(yaml['name']);
print(yaml['description']);
print(yaml['version']);
print(yaml['author']);
print(yaml['homepage']);
print(yaml['dependencies']);
});
}
Regards Robert
None of the above answers worked for me, but here's a working solution for a Flutter app:
In your pubspec.yaml add the "pubspec.yaml" to assets:
assets:
- assets/
- pubspec.yaml
If you have a widget where you need to show the app version like this:
...
Container(
child: Text('Version: 1.0.0+1'),
),
...
Wrap your widget with a FutureBuilder like this:
import 'package:flutter/services.dart';
import 'package:yaml/yaml.dart';
...
FutureBuilder(
future: rootBundle.loadString("pubspec.yaml"),
builder: (context, snapshot) {
String version = "Unknown";
if (snapshot.hasData) {
var yaml = loadYaml(snapshot.data);
version = yaml["version"];
}
return Container(
child: Text(
'Version: $version'
),
);
}),
...
The services rootBundle property contains the resources that were packaged with the application when it was built.
If you want to show the version without the build number, you can split the string like so:
'Version: ${version.split("+")[0]}'
UPDATE: As mentioned by #wildsurfer, this approach has a potential security risk in web development because the pubspec.yaml is shared with the browser!
So assuming that this is for a dart cli application then the #Robert suggestion won't work.
dart_config isn't available for dart 2.x and your pubspec.yaml isn't going to be relative to your cwd except when you are in your development environment
So you need to get the pubspec.yaml relative to the libraries executable path.
This example uses the 'paths' package but it isn't required.
This can be obtained by:
import 'package:path/path.dart';
String pathToYaml = join(dirname(Platform.script.toFilePath()), '../pubspec.yaml');
You can now read the yaml:
import 'package:path/path.dart';
import 'package:yaml/yaml.dart';
String pathToYaml = join(dirname(Platform.script.toFilePath()), '../pubspec.yaml');
File f = new File(pathToYaml);
String yamlText = f.readAsStringSync();
Map yaml = loadYaml(yamlText);
print(yaml['name']);
print(yaml['description']);
print(yaml['version']);
print(yaml['author']);
print(yaml['homepage']);
print(yaml['dependencies']);
});
For Flutter only (Web, Android and IOS)... since October 2020
If you want your app working on Web, Android and IOS use "Package info_plus" instead.
How to Incorporate Automated Version Information into A Dart Command Line App
To update version information in your code without having to package a resource file to be parsed during run time, you can have the information hard coded into an automatically generated dart source file which gets compiled into your binary. The following example hard codes the version, name, and description information into the Map object "meta" in a meta.dart file. The meta.dart file is recreated and overwritten every time the test suite is run in development. To verify the source code has the correct version information, the app's code verifies the version and other meta information against the attributes in the pubspec.yaml file (but only when run as interpreted code in development). If there is a difference from pubspec.yaml, it throws an exception. Once compiled into a binary, it will skip that check as it won't find the pubspec.yaml file, so no error is thrown from the binary. Even if a pubspec.yaml file happens to be around and is found, it only throws an exception and does not create a "meta.dart" source file.
1. Create a MetaUpdate class and save it as "meta_update.dart":
import 'dart:io';
import 'package:yaml/yaml.dart';
import 'meta.dart';
class MetaUpdate {
String pathToYaml = "";
String metaDartFileContents = "";
MetaUpdate(this.pathToYaml);
void writeMetaDartFile(String metaDartFilePath) {
File metaDartFile = File(metaDartFilePath);
String metaDartFileContents = """
/// DO NOT EDIT THIS FILE EXCEPT TO ENTER INITIAL VERSION AND OTHER META INFO
/// THIS FILE IS AUTOMATICALLY OVER WRITTEN BY MetaUpdate
Map<String, String> meta = <String, String>{
"name": "${getPubSpec('name')}",
"description":
// ignore: lines_longer_than_80_chars
"${getPubSpec('description')}",
"version":"${getPubSpec('version')}",
};
""";
metaDartFile.writeAsStringSync(metaDartFileContents);
}
String getPubSpec(String pubSpecParam) {
File f = File(pathToYaml);
String yamlText = f.readAsStringSync();
// ignore: always_specify_types
Map yaml = loadYaml(yamlText);
return yaml[pubSpecParam];
}
void verifyLatestVersionFromPubSpec() {
try {
File f = File(pathToYaml);
//exit if no pubspec found so no warning in production
if (!f.existsSync()) return;
//compare meta.dart with pubspec meta and give warning if difference
if (meta.keys
.where((dynamic e) => (meta[e] != getPubSpec(e)))
.isNotEmpty) {
throw Exception(
"""Version number and other meta attributes in code are different from pubspec.yaml. Please check pubspec.yaml and then run test so that MetaUpdate can update meta information in code, then recompile""");
}
} on Exception {
rethrow;
}
}
}
2. Create a "meta.dart" file:
/// DO NOT EDIT THIS FILE EXCEPT TO ENTER INITIAL VERSION AND OTHER META INFO
/// THIS FILE IS AUTOMATICALLY OVER WRITTEN BY MetaUpdate
Map<String, String> meta = <String, String>{
"name": "Acme Transmogrifier",
"description":
"The best dart application ever.",
"version":"2021.09.001",
};
When you initially create the meta.dart file, copy your specific info from pubspec.yaml. This will later be overwritten each time your MetaUpdate.writeMetaDartFile() is run, changing the contents whenever the info in pubspec.yaml is changed.
3. Implement The Version Update In Your Test Code
Add the following in the first line of Main() in your test code (not the source of the main program, we don't want it to be compiled into the binary), changing the path to meta.dart as appropriate:
MetaUpdate("pubspec.yaml").writeMetaDartFile("lib/src/meta.dart");
4. Add A Meta Check To Your Main Code
Put this in your app's code so it is one of the first methods executed when your app is run - it will generate an exception if there is a difference between the attributes shown in the meta.dart and pubspec.yaml:
MetaUpdate("pubspec.yaml").verifyLatestVersionFromPubSpec();
5. Using
Make sure the Name, Version, and Description information in pubspec.yaml contains the latest information you want reflected in your code.
Import "meta.dart" and insert meta['name'], meta['version'], etc. where you need them to be shown (e.g., in --help or --version messages to be printed to the console).
As long as you run your tests before compiling your code the meta information will be accurately reflected in your code.
You can access pubspec.yaml properties with the official pubspec_parse package from the Dart team.
dart pub add pubspec_parse
import 'dart:io';
import 'package:pubspec_parse/pubspec_parse.dart';
final pubspec = File('pubspec.yaml').readAsStringSync();
final parsed = Pubspec.parse(pubspec);
You can then access typed properties on the parsed object.
You can find supported properties here: https://pub.dev/documentation/pubspec_parse/latest/pubspec_parse/Pubspec-class.html.

How do I find the current directory, in Dart?

I want to know what the current directory is. I don't want to shell out to run pwd. Is there an easy way to do this in Dart?
Indeed there is!
import 'dart:io';
main() {
Directory current = Directory.current;
}
Note: this only works on the command-line, not in the browser.
Read more about the API docs for Directory.current.
Directory.current.path does it if you want a string, Directory.current for a Directory.
(note: Directory is defined in dart:io)

Resources