Flutter将文件作为流读取

时间:2018-07-02 12:41:45

标签: flutter

我希望用户在文本字段中输入文本。当用户单击fab时,文本将作为新行(附加)写入文件。我希望我的应用程序读取文件的内容,并在输入文本字段下方的列表视图中将每一行显示为列表项。当用户输入新文本时,该文本应立即显示在列表视图中。

Preview

我能够做到将文本写入文件中。但是如何读取文件并显示其内容?我应该使用streambuilder吗?下面是我到目前为止所做的代码:

let foo .. in ..

1 个答案:

答案 0 :(得分:0)

File文档中实际显示了将文件作为流读取的示例,但是一旦您完成文件的读取,流就结束了……我认为如果以下情况它不会继续向您发送数据您稍后再写,但是请尝试一下。如果要观察文件的更改,请尝试使用file.watch函数,该函数返回FileSystemEvent的流。监视FileSystemEvent.modify,然后每次获取事件时,您可以调用一个函数来读取文件并重新显示所有内容。

这种设计可能是多余的,因为您可以在init上读取一次文件,并将字符串列表的状态保存在状态变量或状态框架(如Redux)中。由于您正在控制对文件的所有写入操作,除非在写入时出现任何错误,否则您的状态应该是文件中保存的状态,因此反复读取文件毫无意义。这是一个示例类,可以做到这一点:

import 'dart:async';
import 'dart:io';
import 'dart:convert';

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

class ReadFileScreen extends StatefulWidget {
  @override
  ReadFileScreenState createState() {
    return new ReadFileScreenState();
  }

}

class ReadFileScreenState extends State<ReadFileScreen> {
  final myController = TextEditingController();
  final storage = FileStorage();

  List<String> lines = [];

  @override
  void initState() {
    super.initState();
    _loadFile();
  }

  //can not make initState() async, so calling this function asynchronously
  _loadFile() async {
    final String readLines = await storage.readFileAsString();
    debugPrint("readLines: $readLines");
    setState(() {
      lines = readLines.split("\\n"); //Escape the new line 
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Testing'),
      ),
      body: new Column(
        mainAxisSize: MainAxisSize.max,
        mainAxisAlignment: MainAxisAlignment.start,
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: <Widget>[
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: new TextField(
              controller: myController,
              decoration: new InputDecoration(
                hintText: 'Enter the text',
              ),
            ),
          ),
          new Expanded(
            child: new ListView.builder(
              itemCount: lines.length,
                itemBuilder: (context, index) {
                  return new Text(lines[index]); //Replace with ListTile here
            }),
          ),
        ],
      ),
      floatingActionButton: new FloatingActionButton(
        child: new Icon(Icons.save_alt),
        onPressed: () {
          final String enteredText = myController.text;
          storage.writeFile(enteredText);
          myController.clear();
          setState(() {
            lines.add(enteredText);
          });
        },
      ),
    );
  }
}

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

    return directory.path;
  }

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

  Future<String> readFileAsString() async {
    String contents = "";
    final file = await _localFile;
    if (file.existsSync()) { //Must check or error is thrown
      debugPrint("File exists");
      contents = await file.readAsString();
    }
    return contents;
  }

  Future<Null> writeFile(String text) async {
    final file = await _localFile;

    IOSink sink = file.openWrite(mode: FileMode.APPEND);
    sink.add(utf8.encode('$text\n')); //Use newline as the delimiter
    await sink.flush();
    await sink.close();
  }
}