[译]Flutter 操作 XLSX 文件的库 excel

2,013 阅读1分钟

原文链接: excel | Dart Package (flutter-io.cn)

译时版本:2.1.0


Excel 是一用于读写修改 XLSX 文件的 flutter /dart 库。

该库是 MIT 许可,所以无许获得许可即可免费在任何时候任何地方使用,这是因为我们相信开源工作。

开始

1. 依赖

在包的 pubspec.yaml 中添加依赖:

dependencies:
  excel: 2.1.0

2. 安装

可用命令安全包:

使用 pub

$  dart pub add excel

使用 Flutter

$  flutter packages get

3. 导入

现在在 Dart 代码中,可以如下使用:

    import 'package:excel/excel.dart';

用法

从 1.0.8 或更旧版本迁移到 1.0.9 或更新版本 有一些破坏性的变动。

需要修改 updateCell 函数以防代码崩溃。


    excel.updateCell('SheetName', CellIndex.indexByString('A2'), 'Here value', backgroundColorHex: '#1AFF1A', horizontalAlign: HorizontalAlign.Right);

    // 现在在上面的代码中封装了使用 CellStyle() 的可选参数,然后将其传递给可选的 cellStyle 参数。
    // 所以修改后的代码会如下

    excel.updateCell('SheetName', CellIndex.indexByString('A2'), 'Here value', cellStyle: CellStyle( backgroundColorHex: '#1AFF1A', horizontalAlign: HorizontalAlign.Right ) );

导入

    import 'dart:io';
    import 'package:path/path.dart';
    import 'package:excel/excel.dart';

密码保护?protect

Protect 可用于从Excel文件中添加或移除密码保护。

读取 XLSX 文件

    var file = 'Path_to_pre_existing_Excel_File/excel_file.xlsx';
    var bytes = File(file).readAsBytesSync();
    var excel = Excel.decodeBytes(bytes);

    for (var table in excel.tables.keys) {
      print(table); //工作表名
      print(excel.tables[table].maxCols);
      print(excel.tables[table].maxRows);
      for (var row in excel.tables[table].rows) {
        print('$row');
      }
    }

你的 Excel 文件被密码保护了?protect

在 Flutter Web 中读取 XLSX

在 Flutter Web 中使用 FilePicker 选取文件。FilePicker


  /// 在 Flutter Web 中使用 FilePicker 选取文件

  FilePickerResult pickedFile = await FilePicker.platform.pickFiles(
    type: FileType.custom,
    allowedExtensions: ['xlsx'],
    allowMultiple: false,
  );

  /// 文件被选择时

  if (pickedFile != null) {
    var bytes = pickedFile.files.single.bytes;
    var excel = Excel.decodeBytes(bytes);
    for (var table in excel.tables.keys) {
      print(table); //sheet Name
      print(excel.tables[table].maxCols);
      print(excel.tables[table].maxRows);
      for (var row in excel.tables[table].rows) {
        print('$row');
      }
    }
  }

从 Asset 文件夹中读取 XLSX

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

    /* 其他重要代码。。。 */

    ByteData data = await rootBundle.load('assets/existing_excel_file.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].maxCols);
      print(excel.tables[table].maxRows);
      for (var row in excel.tables[table].rows) {
        print('$row');
      }
    }

创建新的 XLSX 文件

    var excel = Excel.createExcel(); // 自动创建一个空的工作表:Sheet1

更新单元格的值

     /*
      * sheetObject.updateCell(cell, value, { CellStyle (Optional)});
      * 调用代码创建的 sheetObject - // Sheet sheetObject = excel['SheetName'];
      * 单元格可用单元格地址或行列二维数组的下标来标识;
      * 单元格样式选项是可选的;
      */

      Sheet sheetObject = excel['SheetName'];

      CellStyle cellStyle = CellStyle(backgroundColorHex: '#1AFF1A', fontFamily : getFontFamily(FontFamily.Calibri));

      cellStyle.underline = Underline.Single; // or Underline.Double


      var cell = sheetObject.cell(CellIndex.indexByString('A1'));
      cell.value = 8; // 可支持 dynamic 类型的值;
      cell.cellStyle = cellStyle;

      // 打印单元格类型
      print('CellType: '+ cell.cellType.toString());

      ///
      /// 插入和移除行列

      // 在下标是8的地方插入列
      sheetObject.insertColumn(8);

      // 移除下标是18的列
      sheetObject.removeColumn(18);

      // 在下标82处插入行
      sheetObject.insertRow(82);

      // 移除下标是 80 的行
      sheetObject.removeRow(80);

单元格样式选项

说明
fontFamily例 getFontFamily(FontFamily.Arial) 或 getFontFamily(FontFamily.Comic_Sans_MS现在共用 182 种字体可用
fontSize指定文字大小的整数值 例 fontSize = 15
bold设置为 true 时,取将文本设为粗体,默认设置为 false
italic设置为 true 时,取将文本设为斜体,默认设置为 false
underline为文本设置下划线 enum Underline { None, Single, Double } 例 Underline.Single,默认为 Underline.None
fontColorHexFont Color 例 '#0000FF'
rotation (degree)文本旋转 例 50,旋转角度从 -9090 ,包含 90 和 -90
backgroundColorHex单元格背景色 例 '#faf487'
wrap文本换行 enum TextWrapping { WrapText, Clip } 例 TextWrapping.Clip (换行)
verticalAlign文本垂直对齐方式 enum VerticalAlign { Top, Center, Bottom } 例 VerticalAlign.Top (居顶)
horizontalAlign文本水平对齐 enum HorizontalAlign { Left, Center, Right } eg. HorizontalAlign.Right (居在)
leftBorder单元格的左边边框 (参考下面说明)
rightBorder单元格的右边边框
topBorder单元格的顶部边框
bottomBorder单元格的底部边框
diagonalBorder单元格的对角线框
diagonalBorderUp标示对角线框显示在上对角时的逻辑值
diagonalBorderDown标示对角线框显示在下对角时的逻辑值

边框

边框为单元格的每个边都进行定义(左、右、顶、底)。 所有的对角线框(上、下)共享相同的设置。 diagonalBorderUpdiagonalBorderDown (或两者)需要设置为 true 以显示需要的对角线。

每个边框都必须是 Border 对象。 该对象接收两个参数:borderStyle 用于选中不同的受支持的样式其中之一,borderColorHex 用于修改边框颜色。

borderStyle 必须是 BorderStyle 枚举值中的一个值:

  • BorderStyle.None
  • BorderStyle.DashDot
  • BorderStyle.DashDotDot
  • BorderStyle.Dashed
  • BorderStyle.Dotted
  • BorderStyle.Double
  • BorderStyle.Hair
  • BorderStyle.Medium
  • BorderStyle.MediumDashDot
  • BorderStyle.MediumDashDotDot
  • BorderStyle.MediumDashed
  • BorderStyle.SlantDashDot
  • BorderStyle.Thick
  • BorderStyle.Thin
     /*
      * 
      * 定义单元格左右两边的边框为细线框,顶部边框为红色细线框,底部边框为蓝色中线框。
      *
      */

      CellStyle cellStyle = CellStyle(
        leftBorder: Border(borderStyle: BorderStyle.Thin),
        rightBorder: Border(borderStyle: BorderStyle.Thin),
        topBorder: Border(borderStyle: BorderStyle.Thin, borderColorHex: 'FFFF0000'),
        bottomBorder: Border(borderStyle: BorderStyle.Medium, borderColorHex: 'FF0000FF'),
      );

编辑工作表为 RTL 从右向左


     /*
      * 将 rtl 设置为 true 使工作表变为 从右向左
      * 默认值为 false ( 意味着新的或默认的工作表是 从左向右 )
      *
      */

      var sheetObject = excel['SheetName'];
      sheetObject.rtl = true;

复制工作表内容到另一个工作表


     /*
      * excel.copy(String 'existingSheetName', String 'anotherSheetName');
      * existingSheetName 要在 excel.tables.keys 中存在,这样才能成功复制
      * 如果不存在,则会自动创建。
      *
      */

      excel.copy('existingSheetName', 'anotherSheetName');

重命名工作表


     /*
      * excel.rename(String 'existingSheetName', String 'newSheetName');
      * existingSheetName 要在 excel.tables.keys 中存在,这样才能成功重命名
      *
      */

      excel.rename('existingSheetName', 'newSheetName');

删除工作表


     /*
      * excel.delete(String 'existingSheetName');
      * (existingSheetName 要在 excel.tables.keys 中存在) 并且 (excel.tables.keys.length >= 2),这样才能成功删除。
      *
      */

      excel.delete('existingSheetName');

链接工作表


     /*
      * excel.link(String 'sheetName', Sheet sheetObject);
      *
      * 任何对 'sheetName' 所指向的工作表对象或 sheetObject 的操作都会在两者上面反映。
      * 如果 'sheetName' 不存在,则会自动创建,然后链接到 sheetObject 的操作。
      *
      */

      excel.link('sheetName', sheetObject);

断开链接工作表


     /*
      * excel.unLink(String 'sheetName');
      * 为了成功断开到 'sheetName' 所指向的工作表的链接,它必须在 excel.tables.keys 中存在
      *
      */

      excel.unLink('sheetName');

      // 调用上面的函数之后,需要确保重新创建指向本身的一个新引用

      Sheet unlinked_sheetObject = excel['sheetName'];

合并单元格

    /*
     * sheetObject.merge(CellIndex starting_cell, CellIndex ending_cell, dynamic 'customValue');
     * 调用函数创建工作表对象 - // Sheet sheetObject = excel['SheetName'];
     * 可用单元格地址或行列二维数组的下标标识合并起始单元格和终止单元格;
     * customValue 是可选的;
     */

      sheetObject.merge(CellIndex.indexByString('A1'), CellIndex.indexByString('E4'), customValue: 'Put this text after merge');

获取合并单元格的单元格列表

      // 检查哪些单元格被合并了

      sheetObject.spannedItems.forEach((cells) {
        print('Merged:' + cells.toString());
      });

解除合并单元格

    /*
     * sheetObject.unMerge(cell);
     * 调用函数创建工作表对象 - // Sheet sheetObject = excel['SheetName'];
     * 只可使用例 'A1:E4' 中的字符串标识单元格。
     * 要检查 'A1:E4' 是否为合并中的单元格,调用 excel.getMergedCells(sheet);
     * 然后验证目标单元格是否在这之内。
     */

      sheetObject.unMerge('A1:E4');

查找/替换

    /*
     * int replacedCount = sheetObject.findAndReplace(source, target);
     * 调用函数创建工作表对象 - // Sheet sheetObject = excel['SheetName'];
     * source 是 字符串或(匹配用户自定义的正则表达式)
     * target 是要替换单元格中 source 的字符串
     *
     * 它会返回被替换的数量
     */

      int replacedCount = sheetObject.findAndReplace('Flutter', 'Google');

迭代插入行

     /*
      * sheetObject.insertRowIterables(list-iterables, rowIndex, iterable-options?);
      * 调用函数创建工作表对象 - // Sheet sheetObject = excel['SheetName'];
      * list-iterables === 要放置到指定行的列表迭代对象
      * rowIndex === 迭代对象要放置的行
      * Iterable options 迭代选项是可选的
      */

      /// 以下代码会将要迭代的列表放到第 8 行
      List<String> dataList = ['Google', 'loves', 'Flutter', 'and', 'Flutter', 'loves', 'Excel'];

      sheetObject.insertRowIterables(dataList, 8);

迭代选项

说明
startingColumn迭代列表起始的起始列
overwriteMergedCellsoverwriteMergedCells 默认为 true ,如果设置为 false 则不会覆盖并会在唯一的单元格中写入

添加 Row

   /*
    * sheetObject.appendRow(list-iterables);
    * 调用函数创建工作表对象 - // Sheet sheetObject = excel['SheetName'];
    * list-iterables === 迭代列表
    */

     sheetObject.appendRow(['Flutter', 'till', 'Eternity']);

获取默认打开的工作表

   /
    * 方法会返回默认工作表的名称
    * excel.getDefaultSheet();
    */

     var defaultSheet = excel.getDefaultSheet();
     print('Default Sheet:' + defaultSheet.toString());

设置默认打开的工作表

   /*
    * 方法会设置默认工作表的名字
    * 如果设置成功会返回 true ,否则返回 false
    * excel.setDefaultSheet(sheet);
    * 
    * sheet = 'SheetName'
    */

     var isSet = excel.setDefaultSheet(sheet);
     if (isSet) {
       print('$sheet is set to default sheet.');
     } else {
       print('Unable to set $sheet to default sheet.');
     }

保存

在 Flutter Web 中

     // 在 flutter web 中时调用 save() 会下载 Excel 文件。

     // 调用 save() 函数下载文件
     var fileBytes = excel.save(fileName: 'My_Excel_File_Name.xlsx');

在 Android / iOS 中

为了在 Android 或 iOS 中获取保存目录,使用:path_provider

    var fileBytes = excel.save();
    var directory = await getApplicationDocumentsDirectory();

    File(join('$directory/output_file_name.xlsx'))
      ..createSync(recursive: true)
      ..writeAsBytesSync(fileBytes);

下一版本的特性

进行中的实现:

  • 公式
  • 转换为 PDF