Saltar al contenido principal

Leer y escribir archivos

Cómo leer y escribir en archivos en el disco.

En algunos casos, necesitas leer y escribir archivos en el disco. Por ejemplo, es posible que necesites persistir datos entre lanzamientos de aplicaciones, o descargar datos de internet y guardarlos para su uso posterior sin conexión.

Para guardar archivos en el disco en aplicaciones móviles o de escritorio, combina el plugin path_provider con la librería dart:io.

Esta receta utiliza los siguientes pasos:

  1. Encontrar la ruta local correcta.
  2. Crear una referencia a la ubicación del archivo.
  3. Escribir datos en el archivo.
  4. Leer datos del archivo.

Para obtener más información, mira este video de Package of the Week sobre el paquete path_provider:

Ver en YouTube en una pestaña nueva: "path_provider | Paquete de la semana de Flutter"

1. Encontrar la ruta local correcta

#

Este ejemplo muestra un contador. Cuando el contador cambia, escribe los datos en el disco para que puedas leerlos nuevamente cuando se cargue la aplicación. ¿Dónde deberías almacenar estos datos?

El paquete path_provider proporciona una forma independiente de la plataforma para acceder a las ubicaciones de uso común en el sistema de archivos del dispositivo. El plugin actualmente admite el acceso a dos ubicaciones del sistema de archivos:

Directorio temporal

A temporary directory (cache) que el sistema puede borrar en cualquier momento. En iOS, esto corresponde al NSCachesDirectory. En Android, este es el valor que devuelve getCacheDir().

Directorio de documentos

Un directorio para que la aplicación almacene archivos a los que solo ella pueda acceder. El sistema borra el directorio solo cuando se elimina la aplicación. En iOS, esto corresponde a NSDocumentDirectory. En Android, este es el directorio AppData.

Este ejemplo almacena información en el directorio de documentos. Puedes encontrar la ruta al directorio de documentos de la siguiente manera:

dart
import 'package:path_provider/path_provider.dart';

  // ···
  Future<String> get _localPath async {
    final directory = await getApplicationDocumentsDirectory();

    return directory.path;
  }

2. Crear una referencia a la ubicación del archivo

#

Una vez que sepas dónde almacenar el archivo, crea una referencia a la ubicación completa del archivo. Puedes utilizar la clase File de la librería dart:io para lograr esto.

dart
Future<File> get _localFile async {
  final path = await _localPath;
  return File('$path/counter.txt');
}

3. Escribir datos en el archivo

#

Ahora que tienes un File con el que trabajar, utilízalo para leer y escribir datos. Primero, escribe algunos datos en el archivo. El contador es un entero, pero se escribe en el archivo como una cadena utilizando la sintaxis '$counter'.

dart
Future<File> writeCounter(int counter) async {
  final file = await _localFile;

  // Write the file
  return file.writeAsString('$counter');
}

4. Leer datos del archivo

#

Ahora que tienes algunos datos en el disco, puedes leerlos. Una vez más, utiliza la clase File.

dart
Future<int> readCounter() async {
  try {
    final file = await _localFile;

    // Read the file
    final contents = await file.readAsString();

    return int.parse(contents);
  } catch (e) {
    // If encountering an error, return 0
    return 0;
  }
}

Ejemplo completo

#
dart
import 'dart:async';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';

void main() {
  runApp(
    MaterialApp(
      title: 'Reading and Writing Files',
      home: FlutterDemo(storage: CounterStorage()),
    ),
  );
}

class CounterStorage {
  Future<String> get _localPath async {
    final directory = await getApplicationDocumentsDirectory();

    return directory.path;
  }

  Future<File> get _localFile async {
    final path = await _localPath;
    return File('$path/counter.txt');
  }

  Future<int> readCounter() async {
    try {
      final file = await _localFile;

      // Read the file
      final contents = await file.readAsString();

      return int.parse(contents);
    } catch (e) {
      // If encountering an error, return 0
      return 0;
    }
  }

  Future<File> writeCounter(int counter) async {
    final file = await _localFile;

    // Write the file
    return file.writeAsString('$counter');
  }
}

class FlutterDemo extends StatefulWidget {
  const FlutterDemo({super.key, required this.storage});

  final CounterStorage storage;

  @override
  State<FlutterDemo> createState() => _FlutterDemoState();
}

class _FlutterDemoState extends State<FlutterDemo> {
  int _counter = 0;

  @override
  void initState() {
    super.initState();
    widget.storage.readCounter().then((value) {
      setState(() {
        _counter = value;
      });
    });
  }

  Future<File> _incrementCounter() {
    setState(() {
      _counter++;
    });

    // Write the variable as a string to the file.
    return widget.storage.writeCounter(_counter);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Reading and Writing Files')),
      body: Center(
        child: Text('Button tapped $_counter time${_counter == 1 ? '' : 's'}.'),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}