Флаттер читает файл как поток - PullRequest
0 голосов
/ 02 июля 2018

Я хочу, чтобы пользователь вводил текст в текстовое поле. Когда пользователь щелкает по значку, текст записывается в файл в виде новой строки (добавление). Я хочу, чтобы мое приложение считывало содержимое файла и показывало каждую строку в виде списка в виде списка под текстовым полем ввода. Когда пользователь вводит новый текст, он должен появиться в списке мгновенно.

Preview

Мне удалось записать текст в файл. Но как прочитать файл и отобразить его содержимое? Должен ли я использовать streambuilder? Ниже приведен код, который я сделал до сих пор:

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

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

void main() {
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Path Provider',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(title: 'Path Provider', storage: FileStorage(),),
    );
  }
}

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

  void readFile() {
    /* What to do? */
  }

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

    IOSink sink = file.openWrite(mode: FileMode.append);
    sink.add(utf8.encode('$text'));
    await sink.flush();
    await sink.close();
  }
}



class MyHomePage extends StatefulWidget {
  final FileStorage storage;
  MyHomePage({Key key, this.title, this.storage}) : super(key: key);
  final String title;

  @override
   _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final myController = TextEditingController();

  @override
  void dispose() {
    // TODO: implement dispose
    myController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    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',
              ),
            ),
          ),
          // StreamBuilder(
          //   stream: widget.storage.readCounter().asStream(),
          // )
        ],
      ),
      floatingActionButton: new FloatingActionButton(
        child: new Icon(Icons.save_alt),
        onPressed: () {
          widget.storage.writeFile(myController.text);
        },
      ),
    );
  }
}

1 Ответ

0 голосов
/ 04 июля 2018

Пример чтения файла в виде потока на самом деле показан в документации Файл , но поток заканчивается, когда вы закончите читать файл ... Я не думаю, что он будет отправлять вам данные, если вы напишите в него позже, но попробуйте. Если вы хотите наблюдать изменения в файле, попробуйте использовать функцию 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();
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...