If you're developing a mobile application using Flutter, you may want to find out how to write a file to device storage and read the content of a file in storage. This tutorial explains how to write and read files using Flutter, including how to get the permission required to perform those operations.
Dependencies
First, install these dependencies by adding them to pubspec.yaml
file.
path_provider
is used to help us getting the directory of the file. simple_permissions
is used for requesting permission.
dependencies:
path_provider: ^0.4.1
simple_permissions: ^0.1.9
Requesting Permission
In Android, to be able to write a file to external storage, the application needs to be granted WRITE_EXTERNAL_STORAGE
permission. That permission also implicitly grants the application READ_EXTERNAL_STORAGE
permission. Like developing an Android application the conventional way with Java, we need to add the permission in AndroidManifest.xml
.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Since Android 6.0 Marshmallow, in order to be granted for a permission, the application needs to ask the user for each permissions by showing a popup. We need to do the same in Flutter. To make it easy, we can use a library such as SimplePermissions
. Here is the example.
bool _allowWriteFile = false;
@override
void initState() {
super.initState();
requestWritePermission();
}
// Platform messages are asynchronous, so we initialize in an async method.
requestWritePermission() async {
PermissionStatus permissionStatus = await SimplePermissions.requestPermission(Permission.WriteExternalStorage);
if (permissionStatus == PermissionStatus.authorized) {
setState(() {
_allowWriteFile = true;
});
}
}
Determining the Directory Path
We need to get the path to the directory where the file is or will be. Usually a file is put in the application's document directory, in the application's cache directory, or in the external storage directory. To get the path easily and reduce the chance of type, we can use PathProvider
class. Below is the example.
Future get _localPath async {
// Application documents directory: /data/user/0/{package_name}/{app_name}
final applicationDirectory = await getApplicationDocumentsDirectory();
// External storage directory: /storage/emulated/0
final externalDirectory = await getExternalStorageDirectory();
// Application temporary directory: /data/user/0/{package_name}/cache
final tempDirectory = await getTemporaryDirectory();
return applicationDirectory.path;
}
Getting the Reference to the File
In order to write to or read a file, we need to get the reference to the file.
Future get _localFile async {
final path = await _localPath;
return File('$path/file-name.txt');
}
Writing to A File
By getting the file reference, we can directly write to the file by using either writeAsString
or writeAsBytes
.
Future _writeToFile(String text) async {
if (!_allowWriteFile) {
return null;
}
final file = await _localFile;
// Write the file
File result = await file.writeAsString('$text');
}
Reading A File
We also need to get the file reference to read a file. Then use readAsString
, readAsBytes
, or readAsLines
.
Future _readFile() async {
try {
final file = await _localFile;
// Read the file
return await file.readAsString();
} catch (e) {
// Return null if we encounter an error
return null;
}
}
Full Code
Below is the full code of this tutorial. First, it writes a string to the file. Then, it reads the same file and prints the result. If successful, we should get the same content.
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';
import 'package:path_provider/path_provider.dart';
import 'package:simple_permissions/simple_permissions.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Welcome to Flutter',
home: _ReadWriteFile(),
);
}
}
class _ReadWriteFileAppState extends State<ReadWriteFile> {
bool _allowWriteFile = false;
Future get _localPath async {
// Application documents directory: /data/user/0/{package_name}/{app_name}
final applicationDirectory = await getApplicationDocumentsDirectory();
// External storage directory: /storage/emulated/0
final externalDirectory = await getExternalStorageDirectory();
// Application temporary directory: /data/user/0/{package_name}/cache
final tempDirectory = await getTemporaryDirectory();
return applicationDirectory.path;
}
Future get _localFile async {
final path = await _localPath;
return File('$path/counterxxx.txt');
}
Future _writeToFile(String text) async {
if (!_allowWriteFile) {
return null;
}
final file = await _localFile;
// Write the file
File result = await file.writeAsString('$text');
if (result == null ) {
print("Writing to file failed");
} else {
print("Successfully writing to file");
print("Reading the content of file");
String readResult = await _readFile();
print("readResult: " + readResult.toString());
}
}
Future _readFile() async {
try {
final file = await _localFile;
// Read the file
return await file.readAsString();
} catch (e) {
// Return null if we encounter an error
return null;
}
}
@override
void initState() {
super.initState();
_requestWritePermission();
}
_requestWritePermission() async {
PermissionStatus permissionStatus = await SimplePermissions._requestPermission(Permission.WriteExternalStorage);
if (permissionStatus == PermissionStatus.authorized) {
setState(() {
_allowWriteFile = true;
});
}
}
@override
Widget build(BuildContext context) {
this._writeToFile("Test");
return Scaffold(
appBar: AppBar(
title: Text('Writing and Reading File Tutorial'),
),
body: Center(
child: Text("by Woolha.com")
)
);
}
}
class ReadWriteFile extends StatefulWidget {
@override
_ReadWriteFileAppState createState() => new _ReadWriteFileAppState();
}