Skip to main content

读取和写入文件

在某些情况下,您需要读取和写入磁盘上的文件。例如,您可能需要在应用程序启动之间保留数据,或者从互联网下载数据并将其保存以供以后脱机使用。

要在移动或桌面应用程序上将文件保存到磁盘,请将path_provider插件与dart:io库结合使用。

此示例使用以下步骤:

  1. 查找正确的本地路径。
  2. 创建对文件位置的引用。
  3. 将数据写入文件。
  4. 从文件读取数据。

要了解更多信息,请观看有关path_provider包的本周包视频:


path_provider | Flutter package of the week

1. 查找正确的本地路径

#

此示例显示一个计数器。当计数器发生变化时,将数据写入磁盘,以便在应用程序加载时再次读取它。您应该在哪里存储此数据?

path_provider包提供了一种与平台无关的方式来访问设备文件系统上的常用位置。此插件目前支持访问两个文件系统位置:

临时目录
系统可以随时清除的临时目录(缓存)。在 iOS 上,这对应于NSCachesDirectory。在 Android 上,这是getCacheDir()返回的值。
文档目录
应用程序存储仅其自身可以访问的文件的目录。仅当应用程序被删除时,系统才会清除此目录。在 iOS 上,这对应于NSDocumentDirectory。在 Android 上,这是AppData目录。

此示例将信息存储在文档目录中。您可以按如下方式找到文档目录的路径:

dart
import 'package:path_provider/path_provider.dart';
  // ···
  Future<String> get _localPath async {
    final directory = await getApplicationDocumentsDirectory();

    return directory.path;
  }

2. 创建对文件位置的引用

#

一旦知道在哪里存储文件,就创建一个对文件完整位置的引用。您可以使用dart:io库中的File类来实现这一点。

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

3. 将数据写入文件

#

现在您有了可以使用的File,可以使用它来读取和写入数据。首先,将一些数据写入文件。计数器是一个整数,但使用'$counter'语法将其作为字符串写入文件。

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

  // 写入文件
  return file.writeAsString('$counter');
}

4. 从文件读取数据

#

现在您在磁盘上有一些数据,您可以读取它。再次使用File类。

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

    // 读取文件
    final contents = await file.readAsString();

    return int.parse(contents);
  } catch (e) {
    // 如果遇到错误,则返回 0
    return 0;
  }
}

完整示例

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

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

void main() {
  runApp(
    MaterialApp(
      title: '读取和写入文件',
      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;

      // 读取文件
      final contents = await file.readAsString();

      return int.parse(contents);
    } catch (e) {
      // 如果遇到错误,则返回 0
      return 0;
    }
  }

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

    // 写入文件
    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++;
    });

    // 将变量作为字符串写入文件。
    return widget.storage.writeCounter(_counter);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('读取和写入文件'),
      ),
      body: Center(
        child: Text(
          '按钮点击了 $_counter${_counter == 1 ? '' : '数'}。',
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: '递增',
        child: const Icon(Icons.add),
      ),
    );
  }
}