【Flutter】ファイルの出力と読込【日本語】

Flutterでのファイルの出力と読込を行ってみます。

初心者の私でも簡単に出来たので、その備忘録となります。

他のプログラミングに関する記事はこちら

スポンサーリンク


【前提】

過去に作成した入力フォームの実装の記事の最下部にある「チラシ裏」のソースコード全文を元に作成しています。

 

【今回試しに作ったもの】

文字を入力して、それをファイル出力する

出力したファイルを読み取り、読み取った内容を画面上に表示させる

 

というアプリを作りました。

 

【ソースコード】

ソースコードは以下の通りです(詳細は後述します)

main.dart

import 'dart:async'; //非同期処理用ライブラリ
import 'dart:io';  //ファイル出力用ライブラリ
import 'package:path_provider/path_provider.dart'; //アプリがファイルを保存可能な場所を取得するライブラリ

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget { 
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'otameshi',
      home: Scaffold(
        appBar: AppBar(
          title: Text('OutputTest'),
        ),
        body: OutputTest(),
      ),
    );
  }
}

class OutputTest extends StatefulWidget{
  @override
  _OutputTestState createState() => new _OutputTestState();
}

class _OutputTestState extends State<OutputTest>{

  // 入力された内容を保持するコントローラ
  final outputController = TextEditingController();

  // 表示用の変数
  String inputText = "0回、出力しました";
  int inputNum = 0;

  // 「ファイルに出力する」が押されたときの処理
  void output(String s) async{
    setState(() {
      ++inputNum;
      inputText = "" + inputNum.toString() + "回、出力しました";
    });
    
    getFilePath().then((File file) { //thenの記述で非同期処理であるgetFilePath関数の処理を待っている
      file.writeAsString(s);
    });
  }

  //ファイルの読み込みと変数への格納処理
  void loadFile() async {
    setState(() {
      load().then((String value) {
        setState(() {
          inputText = value;
        });
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.start,
      children: <Widget>[
        // Column1
        Container(
          alignment: Alignment.center,
          child: Container(
            width: 300,
            height: 100,
            child: TextField(
              enabled: true, //活性or非活性
              maxLength: 10, //入力最大文字数
              style: TextStyle(color: Colors.red), //入力文字のスタイル
              obscureText: false, //trueでマスク(****表記)にする
              maxLines:1, //入力可能行数
              controller: outputController,
            ),
          )
        ),

        // Column2
        GestureDetector(
          onTap: () {
            output(outputController.text);
          },
          child: Text("ファイルに出力する"),
        ),

        // Column3
        GestureDetector(
          onTap: () {
            loadFile();
          },
          child: Text("ファイルを読み込む"),
        ),

        // Column4
        Text(inputText),

      ],
    );
  }
}

//テキストファイルを保存するパスを取得する
Future<File> getFilePath() async { //Future<T> 関数名 asyncで<T>クラスを扱いとする非同期処理をする関数。非同期処理は、実行されると、その終了を待たずに他の処理が実行されます。関数内に1つでも非同期処理が実行される場合は非同期関数となります。
  final directory = await getTemporaryDirectory(); //await はその処理が終わるまで待つということ
  debugPrint(directory.path);
  return File(directory.path + '/test.txt');
}

//テキストファイルの読み込み
Future<String> load() async {
  final file = await getFilePath();
  return file.readAsString();
}

 

pubspec.yaml

name: myapp
description: A new Flutter project.
version: 1.0.0+1

environment:
  sdk: ">=2.1.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  
  path_provider: any

  cupertino_icons: ^0.1.2

dev_dependencies:
  flutter_test:
    sdk: flutter

flutter:
  uses-material-design: true

 

【ファイルの出力の詳細】

まずはじめに、ファイル出力する方法です。

 

ファイル出力するためにはまず、ファイル出力するために必要なライブラリを取得します(ライブラリの導入方法はこちら

必要なのは以下の3つです。

import 'dart:async'; //非同期処理用ライブラリ
import 'dart:io';  //ファイル出力用ライブラリ
import 'package:path_provider/path_provider.dart'; //アプリがファイルを保存可能な場所を取得するライブラリ

 

pubspec.yamlにはdependenciesの項目に「path_provider: any」を記述をします。

dependencies:
  flutter:
    sdk: flutter
  
  path_provider: any

  cupertino_icons: ^0.1.2

 

次に、FutureのgetFilePathを以下の通り作成します。

getFilePathは保存先のディレクトリとファイル名を作成している関数です。

Future<File> getFilePath() async {
  final directory = await getTemporaryDirectory();
  return File(directory.path + '/test.txt');
}

Futureとは、非同期を行うための関数です。

返り値の型は<>で括って指定します。

今回の場合はFile型を返す非同期の関数……ということですね。

 

asyncとは、非同期の関数に付属する言葉です。

getFilePath()関数を非同期で動くようにしているわけですね。

ファイル出力を使う場合は非同期にしなければいけないようです。

 

awaitとは、非同期とは逆でその処理が終わるまで待たせたいときに指定します。

今回はawaitに保存先のディレクトリを取得する関数を設定していますが、そうしないと保存先のディレクトリ情報を取得する前に次の処理が行われてしまい、エラーになります。

 

 

getFilePath関数を作成したら、今度はそれを利用し出力の記述を行います。

出力の記述は以下の通りです。

    getFilePath().then((File file) {
      file.writeAsString(s);
    });

thenはawaitと同じ感じです。

getFilePath()は非同期で動く関数なので、ディレクトリとファイル名を取得する前にその先の処理に進んだら大変です。

なので、thenを指定してあげることでgetFilePath()の完了を待っているわけです。

getFilePath()で返ってきたFile型のオブジェクトは、File型のfileという名前で取得しています

 

最後に、file.writeAsString(s)で出力しています。

sには文字列が入ります。

ここで指定した文字列が出力されるというわけですね。

 

【ファイルの読込の詳細】

ファイルの出力が出来れば、ファイルの読み込みは超簡単です。

 

まず、load関数を作成します。

Future<String> load() async {
  final file = await getFilePath();
  return file.readAsString();
}

getFilePath()で読込先のファイルをfileオブジェクトに格納し、readAsString()で読み込んでいるだけです。

これでload関数を呼び出せばファイルを読み込み、その中身を返してくれるようになります。

 

【まとめ】

ソースコードの内容をざっくりと説明すると、以下のような感じです(冒頭で表記したソースコード全文を元に説明しています)

 

・1~3行目で、必要なライブラリを取得しています(pubspec.yamlの更新も忘れずに行う必要があります)

・107~112行目で、出力先のディレクトリとファイル名を指定する関数を設定してます

・114~118行目で、出力したファイルの中身を取得する関数(読み込むための関数)を設定してます

・84~88行目で、「ファイルに出力する」をクリックしたときにoutput関数を呼び出しています。

・38~48行目で、output関数を設定しています。内容は入力されている文字を出力しているだけです。

・92~97行目で、「ファイルを読み込む」をクリックしたときにloadFile関数を呼び出しています。

・50~59行目で、出力されたファイル内容を読み取り、画面上に表示するための変数に結果を代入しています。

 

他のプログラミングに関する記事はこちら

スポンサーリンク