You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Flutter Windows中从桌面上传Excel(xls)并保存至SQLite数据库

在Flutter Windows中实现Excel(xls)上传并保存到SQLite数据库

1. 添加必要依赖

在pubspec.yaml中引入三个核心依赖:文件选择工具、Excel解析库、Windows兼容的SQLite库:

dependencies:
  file_selector_windows: ^0.9.2
  excel: ^4.0.1
  sqflite_common_ffi: ^2.3.2

执行flutter pub get完成依赖安装。

2. 实现文件选择功能

编写方法打开Windows文件选择器,仅允许选择.xls格式文件:

import 'package:file_selector_windows/file_selector_windows.dart';

Future<String?> selectExcelFile() async {
  const XTypeGroup excelType = XTypeGroup(
    label: 'Excel文件',
    extensions: ['xls'],
  );
  final XFile? selectedFile = await openFile(acceptedTypeGroups: [excelType]);
  return selectedFile?.path;
}

3. 解析Excel文件内容

读取选中的xls文件,解析为符合数据库表结构的数据集(假设Excel第一行为表头,数据从第二行开始,列顺序为:产品名、售价、成本价、数量):

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

Future<List<Map<String, dynamic>>> parseExcel(String filePath) async {
  final List<Map<String, dynamic>> productList = [];
  final fileBytes = File(filePath).readAsBytesSync();
  final excel = Excel.decodeBytes(fileBytes);

  // 遍历第一个工作表的数据行
  for (final table in excel.tables.values) {
    for (int rowIndex = 1; rowIndex < table.maxRows; rowIndex++) {
      final row = table.rows[rowIndex];
      if (row == null || row.any((cell) => cell == null)) continue; // 跳过空行或数据不全的行

      productList.add({
        'product_name': row[0]?.value?.toString() ?? '',
        'product_price': double.tryParse(row[1]?.value?.toString() ?? '0') ?? 0.0,
        'price_cost': double.tryParse(row[2]?.value?.toString() ?? '0') ?? 0.0,
        'product_quantity': int.tryParse(row[3]?.value?.toString() ?? '0') ?? 0,
      });
    }
  }
  return productList;
}

4. SQLite数据库操作

初始化数据库,并实现批量插入数据的方法:

import 'package:sqflite_common_ffi/sqflite_ffi.dart';

// 初始化Windows兼容的SQLite数据库
Future<Database> initDatabase() async {
  sqfliteFfiInit();
  databaseFactory = databaseFactoryFfi;
  return await openDatabase(
    'products.db',
    version: 1,
    onCreate: (db, version) async {
      await db.execute('''
        CREATE TABLE "products" (
          "product_id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
          "product_name" TEXT NOT NULL,
          "product_price" REAL NOT NULL,
          "price_cost" REAL NOT NULL,
          "product_quantity" INTEGER
        )
      ''');
    },
  );
}

// 批量插入解析后的产品数据
Future<void> batchInsertProducts(List<Map<String, dynamic>> products) async {
  final db = await initDatabase();
  await db.transaction((txn) async {
    for (final product in products) {
      await txn.insert(
        'products',
        product,
        conflictAlgorithm: ConflictAlgorithm.replace, // 重复数据时替换,可按需调整
      );
    }
  });
}

5. 整合完整流程

将上述功能整合到UI按钮的点击事件中,完成从选文件到导入数据库的全流程:

import 'package:flutter/material.dart';

// 在页面中添加导入按钮
ElevatedButton(
  onPressed: () async {
    // 1. 选择Excel文件
    final String? filePath = await selectExcelFile();
    if (filePath == null) return;

    // 2. 解析文件内容
    final productData = await parseExcel(filePath);
    if (productData.isEmpty) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Excel中无有效数据')),
      );
      return;
    }

    // 3. 插入数据库
    try {
      await batchInsertProducts(productData);
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('数据导入成功')),
      );
    } catch (e) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('导入失败: ${e.toString()}')),
      );
    }
  },
  child: const Text('选择并导入Excel'),
)

注意事项

  • 需确保Excel文件的列顺序与解析代码中的索引对应,若列顺序不同,需调整row[0]、row[1]等的索引值。
  • 解析时加入了格式容错处理,避免因Excel中数据格式错误导致崩溃,可根据实际需求优化校验逻辑。
  • 打包Windows应用时,需确保程序拥有读取本地文件的权限,桌面应用默认具备该权限。

内容的提问来源于stack exchange,提问作者abderaouf mansouri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 15:30:22