【Flutter】如何读取 excel 文件

上一篇博客介绍了文件选择器 file_picker 的用法,这一篇博文将介绍如何读取 excel 文件。

需要明确的是,Flutter 本身没有提供读取 excel 的组件,所以我们采用了社区的开源解决方案------excel

不过,写作这篇博客时的最新版(4.0.4)有一个 bug,读取 Mac Numbers 和 WPS 创建的 *.xlsx 文件时会抛出如下异常:

复制代码
_Exception (Exception: custom numFmtId starts at 164 but found a value of 41), error happens when I read an excel file using flutter excel package

针对这个问题,有人已经提了 issue,作者暂时还没解决,文章最后我会给出一个临时解决方案。

首先,新建一个页面,中间放置一个 ElevatedButton,用于读取本地 excel 文件。

然后,给按钮增加点击事件处理方法:

dart 复制代码
ElevatedButton(
  onPressed: () {
    // _pickExcelFile();
    _pickExcelFile();
  },
  child: const Text('Import'),
),

其中 _pickExcelFile 方法的实现如下:

dart 复制代码
_pickExcelFile() async {
  // 选择文件
  FilePickerResult? pickedFile = await FilePicker.platform.pickFiles(
    type: FileType.custom,
    allowedExtensions: ['xlsx'],
    allowMultiple: false,
  );

  if (pickedFile != null) {
    // 读取文件内容
    var bytes = await File(pickedFile.files.single.path!).readAsBytes();
    
    // 解析文件
    var excel = Excel.decodeBytes(bytes);
    for (var table in excel.tables.keys) {
      print(table); //sheet Name
      print(excel.tables[table]?.maxColumns);
      print(excel.tables[table]?.maxRows);
      for (var row in excel.tables[table]!.rows) {
        print('$row');
      }
    }
  }
}

一共有 3 个功能:

  1. 选取文件:

    dart 复制代码
    await FilePicker.platform.pickFiles()
  2. 读取文件:

    dart 复制代码
    await File(pickedFile.files.single.path!).readAsBytes();
  3. 解析文件:

    dart 复制代码
    var excel = Excel.decodeBytes(bytes);

以上就是读取本地 excel 文件的代码实现。

如果 excel 文件是 asset 文件,也可以用下面这种方式来读取:

dart 复制代码
_readExcelFile() async {
  ByteData data = await rootBundle.load('assets/test.xlsx');
  var bytes = data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
  var excel = Excel.decodeBytes(bytes);

  for (var table in excel.tables.keys) {
    print(table); //sheet Name
    print(excel.tables[table]!.maxColumns);
    print(excel.tables[table]!.maxRows);
    for (var row in excel.tables[table]!.rows) {
      print('$row');
    }
  }
}

不过要记得在 pubspec.yaml 文件中声明 asset 文件:

yaml 复制代码
assets:
  - assets/address-codes.xlsx
  - assets/test.xlsx

除了读取文件,excel 还支持创建文件:

dart 复制代码
// automatically creates 1 empty sheet: Sheet1
var excel = Excel.createExcel();

剩下的用于操作文件内容的 API 有点多,这里就不介绍了,具体可移步至 excel 文档

最后,我们来看一下如何解决文章开头提到的那个 bug。

异常代码所在的文件是 /src/parser/parse.dart

dart 复制代码
final numFmtId = int.parse(node.getAttribute('numFmtId')!);
final formatCode = node.getAttribute('formatCode')!;
if (numFmtId < 164) {
  throw Exception('custom numFmtId starts at 164 but found a value of $numFmtId');
}

问题就出在 number < 164 这个表达式上。

excel 作者貌似认为 numFmtId 小于164的所有数字格式都是内置格式,但这并不完全准确。

在Excel文件格式中,数字格式 ID 被分为两个范围:

  1. 内置数字格式:Excel提供的标准数字格式,ID 取值范围是 [0, 163]
  2. 自定义数字格式:用户自定义的数字格式,ID 从164开始,在 BIFF8/OOXML 格式中最高可达 391,在 BIFF2-BIFF7 格式中最高可达 65,535。

实际上,某些 Excel 文件可能包含 ID 低于 164 的自定义数字格式,其中包括 ID 为 0 的「常规」格式,而所谓「常规」格式实际上是一种内置格式。作者没有考虑到这一点,直接抛出了异常。

我们把上面那段代码改一下就可以了:

dart 复制代码
if (numFmtId < 164) {
  numFmtId += 164;
}

实际测试没什么问题,Mac Numbers 和 WPS 都能解析得出来。

以上就是 Flutter 中如何读取 excel 文件的实现过程,感谢阅读。

相关推荐
程序员老刘1 天前
跨平台开发地图 | 2026年6月
flutter·ai编程·客户端
悟空瞎说2 天前
Flutter 架构详解:新手必懂底层原理
flutter
SoaringHeart2 天前
Flutter最佳实践:IM聊天文字链接自动识别跳转
前端·flutter
恋猫de小郭2 天前
KMP / CMP 鸿蒙版本 Beta 发布,他有什么特别之处?
android·前端·flutter
Non-existent9873 天前
WPS批量清理单元格空白字符的4种方法-异常数字格式处理-实战
excel·wps
风华圆舞3 天前
Flutter + 鸿蒙 Intents Kit:页面直达能力的完整接入方案
flutter·ui·华为·harmonyos
韩曙亮3 天前
【Flutter】Flutter 组件 ④ ( 组件渲染 的 三棵树理论 | Widget 树 → Element 树 → RenderObject 树 )
flutter·element·widget·renderobject
Channing Lewis3 天前
PHP 解析 Excel 的那些坑:一次“行号错位”引发的数据丢失
开发语言·php·excel
jarreyer3 天前
【数据分析绘图】excel绘图和bi工具区别
数据挖掘·数据分析·excel
恋猫de小郭3 天前
Android 17 正式版发布,全新 AI 和各种破坏性更新
android·前端·flutter