Flutter: How to display a short text file from ass

2019-08-17 17:53发布

I have ckecked all the answers about reading and writing file in Flutter. None of them answers the question of how to display a text file on the screen of the phone.

All I want to do is to have a function/method to call with the filename as input, which will display a short text file from my assets directory on a new screen on the phone that I have navigated to. The file is correctly placed in assets and mentioned in the yaml file. I have seen the suggestion to use:

Future loadAsset() async {
return await rootBundle.loadString('assets/my_text.txt');
}

but I don't know how to use it and what code to use to display a file on the screen.

3条回答
Luminary・发光体
2楼-- · 2019-08-17 17:58

I suppose that you know how to display a Text on the Screen, so I will just try to explain how I normally read files.

First you have to import:

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

and then, in your class, you can use this:

Future<void> readMyFile() async {
  Directory directory = await getApplicationDocumentsDirectory();
  var _localFilePath = (directory.path + "yourfile.txt");

     if (FileSystemEntity.typeSync(_localFilePath) == FileSystemEntityType.file) {
       final myFile = await _localFile(_localFilePath);
       List<String> linesAsList = await myFile.readAsLinesSync();

    for (var i = 0; i < linesAsList.length; i++) {
      //print("Line No: " + i.toString() + "\n");
      print(linesAsList[i]);
    }
  }
}

Future<File> _localFile(String myPath) async {
  return File(myPath);
}

At the end, the content of your file is in linesAsList as a list of lines.

查看更多
我只想做你的唯一
3楼-- · 2019-08-17 18:01

First this code to have a new screen and call your code:

child: 
FlatButton(
  onPressed: () {
    Navigator.pushNamed(context, '/indled');
    setState(() {
      ReadFile(fileName: 'myfile.txt');
      print('Button 1 got pressed');
    });
    },
    ......

It prints Button 1 got pressed on console and goes fine to new screen indled, which has the code:

class Indled extends StatelessWidget {
@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text('Indledning'),
  ),
  body: Column(
    crossAxisAlignment: CrossAxisAlignment.stretch,
    children: <Widget>[
      Expanded(
        child: Container(
          padding: EdgeInsets.all(8.0),
          child: Text('Indledning 2'),

It prints 'Indledning 2' on the screen as a test, but nothing more happens. I have your code as the following in a separate file:

class ReadFile {
ReadFile({this.fileName});

final String fileName;

Future<void> readMyFile() async {
Directory directory = await      getApplicationDocumentsDirectory();
var _localFilePath = (directory.path + "myfile.txt");

if (FileSystemEntity.typeSync(_localFilePath) ==
    FileSystemEntityType.file) {
  final myFile = await _localFile(_localFilePath);
  List<String> linesAsList = myFile.readAsLinesSync();

  for (var i = 0; i < linesAsList.length; i++) {
    //print("Line No: " + i.toString() + "\n");
    print(linesAsList[i]);
  }
}
}

Future<File> _localFile(String myPath) async {
return File(myPath);
}
}

On the line: List linesAsList = await myFile.readAsLinesSync(); I get a warning on await: Await only futures so I took out await. But same result if await is included.

I have tried to put fileName instead of "my file.txt" in your code, but same result.

查看更多
迷人小祖宗
4楼-- · 2019-08-17 18:05

This is my example code:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show rootBundle;

void main() {
  runApp(Test());
}

class Test extends StatefulWidget {
  @override
  _TestState createState() => _TestState();
}

class _TestState extends State<Test> {
  Future _future;

  Future<String> loadString() async =>
      await rootBundle.loadString('assets/text.txt');

  @override
  void initState() {
    _future = loadString();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: FutureBuilder(
            future: _future,
            builder: (context, snapshot) =>
                Text(snapshot.hasData ? '${snapshot.data}' : ' Reading...')),
      ),
    );
  }
}

Things you must be aware of, we are creating:

Future _future;

Because, it's StatefulWidget and in every interaction State class rebuilds itself, so your app will execute FutureBuilder every time, which is very bad.

loadString method is async with String return type, if you are a beginner for Flutter, use FutureBuilder to handle Future returns for now. There are other ways more useful but a bit advanced.

Don't build the widget unless you are sure FutureBuilder gets the data with this conditional:

snapshot.hasData ? a : b; //or use if(){} else{} for more readable code
查看更多
登录 后发表回答