Flutter - Reading and Writing Files Example

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();
  }