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

Flutter Web使用file_picker处理CSV数据的字段拼接与索引越界问题

Flutter Web处理CSV文件的两个问题:字段拼接混乱与索引越界

在Flutter Web中使用file_picker包读取CSV文件,尝试拆分数据并插入数据库时遇到两个问题:

  • 拆分后行末字段会与下一行首字段拼接,导致数据混乱;
  • 运行时触发RangeError索引越界错误。

原代码

Future<String> pickFile() async {
    FilePickerResult? result = await FilePicker.platform.pickFiles(
      dialogTitle: 'Selecione o arquivo',
      allowMultiple: true,
      type: FileType.custom,
      allowedExtensions: ['csv'],
    );

    if (result != null && result.files.isNotEmpty) {
      var fileBytes = result.files.first.bytes;
      var formater = String.fromCharCodes(fileBytes!);

      //print(formater);

      List<String> listCsv = formater.split(";");

      String nome = '';
      String telefone = '';
      String email = '';
      String cpf = '';

      for (int i = 0; i < listCsv.length; i += 4) {
        nome = listCsv[i];
        telefone = listCsv[i + 1];
        email = listCsv[i + 2];
        cpf = listCsv[i + 3];

        print(RegistersModel(name: nome, phone: telefone, cpf: cpf, email: email));
      }

      //final path = result.files.single.path;
      //print(path);

      return csv = formater;
    } else {
      return 'O documento não foi retornado';
    }
  }

错误输出

GeneralRegistersModel (id: null, name: Hadila, email: hadila.teste@gmail.com, phone: (16)96584-3216, cpf: 154.368.954-94
Ana, idUser: null)
GeneralRegistersModel (id: null, name: (16)96584-3215, email: 154.368.954-93
Amanda, phone: ana.teste@gmail.com, cpf: (16)96584-3214, idUser: null)
GeneralRegistersModel (id: null, name: amanda.teste@gmail.com, email: (16)96584-3213, phone: 154.368.954-92
Bruno, cpf: bruno.teste@gmail.com, idUser: null)
GeneralRegistersModel (id: null, name: 154.368.954-91
Vanesa, email: vanessa.teste@gmail.com, phone: (16)96584-3212, cpf: 154.368.954-90
Jonas, idUser: null)
GeneralRegistersModel (id: null, name: (16)96584-3211, email: 154.368.954-89
Murilo, phone: jonas.teste@gmail.com, cpf: (16)96584-3210, idUser: null)
GeneralRegistersModel (id: null, name: murilo.teste@gmail.com, email: (16)96584-3209, phone: 154.368.954-88
Daniel, cpf: daniel.teste@gmail.com, idUser: null)
GeneralRegistersModel (id: null, name: 154.368.954-87
Bianca, email: bianca.teste@gmail.com, phone: (16)96584-3208, cpf: 154.368.954-86
Pamela, idUser: null)
GeneralRegistersModel (id: null, name: (16)96584-3207, email: 154.368.954-85
Roberto, phone: pamela.teste@gmail.com, cpf: (16)96584-3206, idUser: null)
GeneralRegistersModel (id: null, name: roberto.teste@gmail.com, email: (16)96584-3205, phone: 154.368.954-84
Fabricio, cpf: vfabricio.teste@gmail.com, idUser: null)
GeneralRegistersModel (id: null, name: 154.368.954-83
Claudia, email: claudia.teste@gmail.com, phone: (16)96584-3204, cpf: 154.368.954-82
Pablo, idUser: null)
Error: RangeError (index): Index out of range: index should be less than 43: 43
    at Object.throw_ [as throw] (http://localhost:55593/dart_sdk.js:5080:11)
    at [dartx._get] (http://localhost:55593/dart_sdk.js:17547:21)
    at general_registers_controller.GeneralRegistersController.new.pickFile (http://localhost:55593/packages/project_002_italian_citizenship/src/controllers/general_registers_controller.dart.lib.js:169:33)
    at pickFile.next (<anonymous>)
    at http://localhost:55593/dart_sdk.js:40641:33
    at _RootZone.runUnary (http://localhost:55593/dart_sdk.js:40511:59)
    at _FutureListener.thenAwait.handleValue (http://localhost:55593/dart_sdk.js:35438:29)
    at handleValueCallback (http://localhost:55593/dart_sdk.js:35999:49)
    at _Future._propagateToListeners (http://localhost:55593/dart_sdk.js:36037:17)
    at [_completeWithValue] (http://localhost:55593/dart_sdk.js:35872:23)
    at async._AsyncCallbackEntry.new.callback (http://localhost:55593/dart_sdk.js:35906:35)
    at Object._microtaskLoop (http://localhost:55593/dart_sdk.js:40778:13)
    at _startMicrotaskLoop (http://localhost:55593/dart_sdk.js:40784:13)
    at http://localhost:55593/dart_sdk.js:36261:9

问题原因

  1. 字段拼接混乱:CSV文件以换行符区分每行,原代码直接用;拆分整个文件内容,没有先按行分割,导致行末字段与下一行首字段被合并成一个元素。
  2. 索引越界:原代码假设拆分后的列表长度是4的整数倍,但实际因为换行符的存在,元素总数不是4的倍数,循环中i+3会超出列表最大索引。

修复方案

核心思路

先按换行符分割CSV内容为单独行,再逐行拆分字段,同时加入格式校验避免索引越界。

修复后的代码

Future<String> pickFile() async {
  FilePickerResult? result = await FilePicker.platform.pickFiles(
    dialogTitle: 'Selecione o arquivo',
    allowMultiple: true,
    type: FileType.custom,
    allowedExtensions: ['csv'],
  );

  if (result != null && result.files.isNotEmpty) {
    var fileBytes = result.files.first.bytes;
    var formater = String.fromCharCodes(fileBytes!);

    // 兼容Windows(\r\n)和Unix(\n)换行符,分割成每行
    List<String> rows = formater.split(RegExp(r'\r?\n'));

    // 遍历每行处理(如果CSV有表头,可从rowIndex=1开始跳过表头)
    for (int rowIndex = 0; rowIndex < rows.length; rowIndex++) {
      String row = rows[rowIndex].trim();
      // 跳过空行
      if (row.isEmpty) continue;

      List<String> fields = row.split(';');
      // 校验字段数量是否符合预期(4个字段)
      if (fields.length != 4) {
        print('第${rowIndex+1}行格式错误,字段数量不符:$row');
        continue;
      }

      String nome = fields[0].trim();
      String telefone = fields[1].trim();
      String email = fields[2].trim();
      String cpf = fields[3].trim();

      print(RegistersModel(name: nome, phone: telefone, cpf: cpf, email: email));
    }

    return csv = formater;
  } else {
    return 'O documento não foi retornado';
  }
}

额外建议

  • 如果CSV字段可能包含;(比如字段值带分号),手动拆分容易出错,推荐使用专业的CSV解析包处理,它能正确解析带引号的特殊字段。
  • 加入错误日志,方便定位格式异常的行,提升代码健壮性。

内容的提问来源于stack exchange,提问作者Duas Vias

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 21:21:13