25. 플러터 : 텍스트 파일 읽기

플러터는 그만하려고 했는데..
경험 없는 사람들에게는 이런저런 것들도 필요하구나.. 하는 생각이 들었다.
우재, 너 말이야!

간단하게 텍스트 파일을 읽어서 출력할건데..
우재가 프로젝트에서 했던 것처럼 테이블로 표시해 볼께.

플러터 문서에 보면 순서가 정의되어 있는데..
실제로는 누락된 부분이 있어서 한번에 성공하지 못했다. (참고 사이트)


먼저 path_provider 플러그인을 설치하라고 되어 있다.
클릭하면 아래 페이지로 이동한다.


라이브러리를 추가하기 위해서는 pubspec.yaml 파일을 수정해야 한다.
dependencies: 항목을 찾아 다른 라이브러리하고 똑같은 형식으로 입력한다.

  path_provider: 0.5.0+1

pubspec.yaml 파일 상단에는 패키지 명령 몇 가지가 항상 표시된다.
그 중에서 get이나 upgrade 명령을 선택해서
path_provider 라이브러리를 프로젝트에 반영하면 준비 완료.


헐.. 지금까지 설명한 부분은 앱 내부에서 파일을 만들고 접근하는 방법.
미리 만들어 놓은 파일을 읽기 위해서는 사용할 수 없다.
모든 리소스는 패키지로 묶이기 때문에 앞의 코드로는 파일에 접근할 수 없고
플러터에서 제공하는 애셋 관리자를 사용해서 접근해야 한다.

지금 하려고 하는 것처럼 assets 폴더 아래에 파일을 만들었다면
앞의 코드를 사용할 수 없다는 말.
여기서는 '2016_GDP.txt' 파일을 사용한다.

2016_GDP.txt


pubspec.yaml 파일에 아래와 같이 접근할 수 있도록 명시한다.

dev_dependencies:
flutter_test:
sdk: flutter

flutter:
uses-material-design: true
assets:
- assets/2016_GDP.txt


이번 코드에서 가장 어려운 부분은 Future<String>과 FutureBuilder 클래스 사용법인데..
코드에 주석으로 달아놨으니까.. 읽어보고.

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() => runApp(MaterialApp(home: MyApp()));

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('파일 읽기')),
body: SingleChildScrollView( // 수직 스크롤 지원
child: FutureBuilder(
future: loadAsset('assets/2016_GDP.txt'),
builder: (context, snapshot) {
// snapshot은 Future 클래스가 포장하고 있는 객체를 data 속성으로 전달
// Future<String>이기 때문에 data는 String이 된다.
final contents = snapshot.data.toString();

// 개행 단위로 분리
final rows = contents.split('\n');

var tableRows = <TableRow>[];
for(var row in rows) {
// 이번 파일에서 구분 문자는 콜론(:)
var cols = row.split(':');

// 마지막 줄은 빈 줄이라서 컬럼 개수가 3개가 아니다.
if(cols.length != 3)
continue;

// map 함수를 이용해서 문자열 각각에 대해 Text 위젯 생성
var widgets = cols.map((s) => Text(s));
tableRows.add(TableRow(children: widgets.toList()));
}
return Table(children: tableRows);
},
),
),
);
}

// assets 폴더 아래에 2016_GDP.txt 파일 있어야 함.
// AssetBundle 객체를 통해 리소스에 접근.
// DefaultAssetBundle 클래스 또는 미리 만들어 놓은 rootBundle 객체 사용.
// async는 비동기 함수, await는 비동기 작업이 종료될 때까지 기다린다는 뜻.
// 그러나, 함수 자체가 블록되지는 않고 예약 전달의 형태로 함수 반환됨.
// 따라서 Future 클래스를 사용하기 위해서는 FutureBuilder 등의 특별한 클래스가 필요함.
Future<String> loadAsset(String path) async {
return await rootBundle.loadString(path);
// return await DefaultAssetBundle.of(ctx).loadString('assets/2016_GDP.txt');
}
}