ピュアDart / Flutter で Excel ファイルを生成・保存する
photo from Unsplash/@impelling
excelライブラリとpath_providerライブラリを使用してエクセルファイルを生成、保存する方法です。
エクセルファイルの生成
(使用バージョン)
excel: ^2.0.0-null-safety-3
path_provider: ^2.0.5
ピュアDart (Macのみ検証)
import 'dart:io';
import 'package:excel/excel.dart';
void main() {
// OSのユーザー名を入れる
const user = 'user';
const fileName = 'test';
// Macの場合
const path = '/Users/$user/Desktop/$fileName.xlsx';
// 1.
final Excel excel = Excel.createExcel();
final Sheet sheet1 = excel['Sheet1'];
final Data cell = sheet1.cell(
CellIndex.indexByColumnRow(columnIndex: 0, rowIndex: 0),
);
cell.value = 'アイウエオ';
// 2.
final List<int>? bytes = excel.encode();
if (bytes != null) {
File(path)
..createSync(recursive: true)
..writeAsBytesSync(bytes);
}
}
1. エクセルオブジェクトの生成とセルデータの設定
Excel.createExcel() でExcelオブジェクトを生成します。
Excelオブジェクトは [ ] オペレーター が定義されており、シート名の文字列を指定することでSheetオブジェクトを取得できます。
Sheetオブジェクトの cellメソッド はDataオブジェクトを返します。
Dataオブジェクトはセルの値、スタイル、セルの種類(文字、数字、日付など)、番地などの情報をプロパティとして持ちます。
2. エクセルオブジェクトのデータ化とファイル生成
Excel().encode() でエクセルオブジェクトを dart:io の File に書き込める形式(バイト配列)に変換します。
File().createSync() でファイル生成、
File().writeAsBytesSync() でファイルにデータを書き込みます。
createSyncのrecursiveがtrueの場合はディレクトリが存在しない場合に生成します。
Flutter (Web, iOS, macOS, Androidのエミュレーターで検証)
class MyHomePage extends StatelessWidget {
const MyHomePage({Key? key}) : super(key: key);
void _create() async {
final Excel excel = Excel.createExcel();
final Sheet sheet1 = excel['Sheet1'];
final CellStyle cellStyle = CellStyle(
bold: true,
underline: Underline.Double,
fontSize: 100,
fontColorHex: '#FF0000',
backgroundColorHex: '#FFFF00',
);
final Data cell = sheet1.cell(CellIndex.indexByString('A1'));
cell.cellStyle = cellStyle;
cell.value = 'あいうえお';
const fileName = 'test.xlsx';
// 1. Flutter Web
final List<int>? fileBytes = excel.save(fileName: fileName);
// Web対応だけなら以降必要なし
if (!kIsWeb && fileBytes != null) {
late final String? path;
if (defaultTargetPlatform == TargetPlatform.android) {
// 2. Android
path = '/storage/emulated/0/Download';
} else if (defaultTargetPlatform == TargetPlatform.iOS) {
// 3. iOS
path = (await getApplicationDocumentsDirectory()).path;
} else if (defaultTargetPlatform == TargetPlatform.macOS) {
// 4. macOS
path = (await getDownloadsDirectory())?.path;
}
if (path != null) {
File('$path/$fileName')
..createSync(recursive: true)
..writeAsBytesSync(fileBytes);
}
}
}
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
child: const Text('create'),
onPressed: _create,
),
),
);
}
}
1. Webの場合
Excel().save() を実行することで生成したデータをダウンロードします。Webだけに対応させる場合は以降の処理は必要ないです。
Web以外でも対応させる場合は、ファイル保存の処理に使うためにsaveメソッドが返すバイト配列を変数に保存しておきます。
2. Androidの場合 (APIレベル30と31で検証)
ここではpath_providerを使わずに、ファイルアプリの 「ダウンロード」フォルダ へのパスを直接指定しています。このフォルダにファイルを保存する場合は特別な設定は必要ないようです。
path_providerの getExternalStorageDirectory() を使っても良かったのですが、階層が深くなってユーザー目線的に不便かなと思いこのようにしています。
3. iOSの場合 (14.5で検証)
path_providerの getApplicationDocumentsDirectory() を使用。「ファイル」アプリからこのドキュメントフォルダへアクセスするには Info.plist で次のように指定する必要があります(参考)。
<plist version="1.0">
<dict>
//(省略)
<key>UISupportsDocumentBrowser</key>
<true/>
</dict>
</plist>
ファイルアプリ
4. macOSの場合 (Big Surで検証)
path_providerの getDownloadsDirectory() を使用。entitlementsファイルを次のように指定して、書き込み許可を与える必要があります(参考)。
<plist version="1.0">
<dict>
//(省略)
<key>com.apple.security.files.downloads.read-write</key>
<true/>
</dict>
</plist>
Flutterで作成するmacOSアプリはデフォルトでサンドボックス化されているとのことで、アプリ自身が読み書きできるフォルダは制限されているようです。
(参考)
最後に
Flutterにおけるエクセルファイル関連のライブラリはこちらも人気です。
excelライブラリより高機能みたいなのですが、ピュアDartでは使えないみたいなので今回は使用しませんでした。
syncfusion_flutter_xlsio を使うにはSyncfusion社のコミュニティライセンスが必要みたいです(一定規模の開発でのライセンス取得は無料)が、ライブラリの使用にあたりライセンスキーの入力などは必要ありません。
Discussion