Flutter 中文文档:文件读写

640?wx_fmt=jpeg

磁盘文件的读写操作可能会相对方便地实现某些业务场景。它常见于应用启动期间产生的持久化数据,或者从网络下载数据供离线使用。

为了将文件保存到磁盘,你需要结合使用 dart:io 库中的 path_provider 这个 package。

步骤

  1. 找到正确的本地路径

  2. 创建一个指向文件位置的引用

  3. 将数据写入文件

  4. 从文件读取数据

1. 找到正确的本地路径

这个例子里,我们将会显示一个计数器,当计数器发生变化时,你将在磁盘中写入数据,以便在应用加载时重新读取这些数据。因此,你一定想知道:我应该将这些数据存储在哪里?

path_provider 这个 package 提供了一种与平台无关的方法,用于访问设备文件系统上的常用位置。该插件目前支持访问两个文件系统位置

  • 临时文件夹: 这是一个系统可以随时清空的临时(缓存)文件夹。在 iOS 上对应 NSCachesDirectory 的返回值;在 Android 上对应 getCacheDir() 的返回值。

  • Documents 目录: 供应用使用,用于存储只能由该应用访问的文件。只有在删除应用时,系统才会清除这个目录。在 iOS 上,这个目录对应于 NSDocumentDirectory。在 Android 上,则是 AppData 目录。

在本示例中,你需要将信息存储在 Documents 目录中。可以按如下所示,找到 Documents 目录路径:

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

  return directory.path;
}

2. 创建一个指向文件位置的引用

确定文件的存储位置后,需要创建对文件完整位置的引用。 为此,你可以使用  dart:io  库的  File  类来实现。
Future<File> get _localFile async {
  final path = await _localPath;
  return File('$path/counter.txt');
}
3. 将数据写入文件
现在你已经有了可以使用的  File ,接下来使用这个文件来读写数据。 首先,将一些数据写入该文件。 由于使用了计数器,因此只需将整数存储为字符串格式,使用  '$counter'  即可调用。
Future<File> writeCounter(int counter) async {
  final file = await _localFile;

  // Write the file.
  return file.writeAsString('$counter');
}
Future<File> writeCounter(int counter) async {
  final file = await _localFile;

  // Write the file.
  return file.writeAsString('$counter');
}
4. 从文件读取数据
现在,你的磁盘上已经有了一些数据可供读取。 此时同样需要使用  File  类。
Future<int> readCounter() async {
  try {
    final file = await _localFile;

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

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

测试

为了测试代码与文件的交互情况,你需要对  MethodChannel  发起模拟调用。   MethodChannel  是 Flutter 用于与主平台通信的类。 出于安全起见,在这些测试中是无法与设备上的文件系统进行交互的,你将会与测试环境的文件系统进行交互。
要模拟方法调用,请在测试文件中提供  setupAll  函数。 这样会先运行这个函数,然后再执行测试。
setUpAll(() async {

  // Create a temporary directory. (提供一个临时文件夹作为工作空间)
  final directory = await Directory.systemTemp.createTemp();

  // Mock out the MethodChannel for the path_provider plugin. (为 path_provider 插件提供一个模拟的 MethodChannel)  
  const MethodChannel('plugins.flutter.io/path_provider')
      .setMockMethodCallHandler((MethodCall methodCall) async {
    // If you're getting the apps documents directory, return the path to the
    // temp directory on the test environment instead. (如果您要获取应用的 Documents 目录,请返回测试环境中的临时目录的路径)
    if (methodCall.method == 'getApplicationDocumentsDirectory') {
      return directory.path;
    }
    return null;
  });
});
完整样例
import 'dart:async';
import 'dart:io';

import 'package:flutter/foundation.dart';
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
      String 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 {
  final CounterStorage storage;

  FlutterDemo({Key key, @required this.storage}) : super(key: key);

  @override
  _FlutterDemoState createState() => _FlutterDemoState();
}

class _FlutterDemoState extends State<FlutterDemo> {
  int _counter;

  @override
  void initState() {
    super.initState();
    widget.storage.readCounter().then((int 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: Text('Reading and Writing Files')),
      body: Center(
        child: Text(
          'Button tapped $_counter time${_counter == 1 ? '' : 's'}.',
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

640?wx_fmt=png

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: Age of Ai 设计师:meimeiellie 返回首页