Dart readAsStringSync无法读取包含特殊字符(句点/圆点)的行。

huangapple go评论54阅读模式
英文:

Dart readAsStringSync not reading lines containing a special character (a dot/full stop)

问题

It appears that the "statistic" lines are not being read properly in your import routine. This issue could be due to the way the CSV file is structured or how you are reading the file. Here are a few things to check:

  1. File Structure: Make sure that the "statistic" lines in your CSV file have the same structure as the other lines, with comma-separated values and line breaks. Check for any hidden characters or formatting issues in those lines.

  2. Line Breaks: Ensure that there are consistent line breaks (e.g., "\n" or "\r\n") between each line in the CSV file, including the "statistic" lines. Inconsistent line breaks can lead to issues in reading the file.

  3. Encoding: Verify that the file encoding is consistent and matches the encoding you are using to read the file. In some cases, encoding mismatches can cause problems in reading specific lines.

  4. Debugging: Print out the content of the "temp" variable after reading the file to the console to inspect the entire file content. This can help identify if the issue is with reading or processing specific lines.

  5. Error Handling: Implement error handling to check for any exceptions or errors that might occur during file reading. This can provide more insights into why certain lines are not being read correctly.

  6. File Validation: Double-check that there are no issues with the creation of the CSV file itself, such as missing "statistic" lines during the export process.

By thoroughly checking these aspects, you should be able to identify the root cause of why the "statistic" lines are not being read properly during the import process.

英文:

I am writing a data export/import feature in my application. The output is written as text to a csv file and this appears to be working ok, but the data import is skipping some of the exported lines (the "statistic" data in the output csv file below) and I can’t understand why this is happening.

So you can see how the file is built, the export routine looks like this:

//
// Default to read files from the documents director
final directory =
    await ExternalPath.getExternalStoragePublicDirectory(
        ExternalPath.DIRECTORY_DOWNLOADS);
//
// Build filename
String filename = 'frequentBackup';
filename = filename + DateTime.now().year.toString();
filename =
    filename + DateTime.now().month.toString().padLeft(2, '0');
filename =
   filename + DateTime.now().day.toString().padLeft(2, '0');
filename = '$filename.csv';
String fullname = '$directory/$filename'; // Add path
//
// Build output and save to disk
try {
  //
  // Export Instruments
  File(fullname).writeAsStringSync(exportInstruments(),
      mode: FileMode.write, flush: true);
  //
  // Export Range Names
  File(fullname).writeAsStringSync(exportRanges(),
      mode: FileMode.append, flush: true);
  //
  // Export Frequencies
  File(fullname).writeAsStringSync(exportFrequencies(),
      mode: FileMode.append, flush: true);
  //
  // Export FrequencySort
  File(fullname).writeAsStringSync(
      await exportFrequencySort(database: widget._db),
      mode: FileMode.append,
      flush: true);
  //
  // Export Statistics
  File(fullname).writeAsStringSync(
      await exportStatistics(database: widget._db),
      mode: FileMode.append,
      flush: true);
  //
  // Export AppSettings
  await File(fullname).writeAsString(exportAppSettings(),
      mode: FileMode.append, flush: true);
  //
  // Notify user that the export is complete
  String message = 'Export to $filename complete.';
  showSnackBar(message: message);

The individual functions to create the export rows look like this:

Instrument Data:

String exportInstruments() {
  String output = '';
  Map<int, String> instruments = Instruments.data();

  instruments.forEach((id, name) {
    output += 'instrument,';
    output += 'id:$id,';
    output += 'name:$name\n';
  });
  return output;
}

Range Data:

String exportRanges() {
  String output = '';
  Map<int, String> ranges = Ranges.data();

  ranges.forEach((id, name) {
    output += 'range name,';
    output += 'id:$id,';
    output += 'name:$name\n';
  });
  return output;
}

Frequency Data:

String exportFrequencies() {
  String output = '';
  List<Record> frequencies = Frequencies.master();

  for (Record r in frequencies) {
    output += 'frequency,';
    output += 'fid:${r.id},';
    output += 'iid:${r.instrumentID},';
    output += 'iname:${r.instrument},';
    output += 'rid:${r.rangeNameID},';
    output += 'rname:${r.rangeName},';
    output += 'rtype:${r.rangeType},';
    output += 'fstart:${r.freqStart},';
    output += 'fend:${r.freqEnd},';
    output += 'fundamental:${r.fundamental},';
    output += 'audiofile:${r.audioFile},';
    output += 'audiopath:${r.audioPath} \n';
  }
  return output;
}

Frequency Sort Data:

Future<String> exportFrequencySort({required MyDatabase database}) async {
  String output = '';

  // Get statistics records from the database (Future)
  await DataFrequencies.getSortOrder(db: database).then((order) {
    order.forEach((position, fid) {
      output += 'frequencyorder,';
      output += 'position:$position,';
      output += 'fid:$fid\n';
    });
  });

  return output;
}

Statistic Data:

Future<String> exportStatistics({required MyDatabase database}) async {
  String output = '';

  // Get statistics records from the database (Future)
  await DataStatistics.getAllStatistics(db: database).then((statistics) {
    for (StatRecord s in statistics) {
      output += 'statistic,';
      output += 'type:${s.type.toString()},';
      output += 'fid:${s.id},';
      output += 'iid:${s.iid},';
      output += 'rid:${s.rid},';
      output += 'presented:${s.presented},';
      output += 'correct:${s.correct}\n';
    }
  });
  return output;
}

App Setting Data:

String exportAppSettings() {
  String output = '';
  Map<String, dynamic> settings = Settings.getAllSettings();

  settings.forEach((name, setting) {
    output += 'setting,';
    output += 'name:$name,';
    output += 'setting:$setting\n';
  });
  return output;
}

The output csv file produced by these functions looks like this:

instrument,id:1,name:banjo 
instrument,id:2,name:piano
instrument,id:3,name:xylophone 
range name,id:1,name:crump
range name,id:2,name:kapow
range name,id:3,name:whump
frequency,fid:1,iid:1,iname:banjo ,rid:1,rname:crump,rtype:R,fstart:30,fend:60,fundamental:1,audiofile:,audiopath: 
frequency,fid:2,iid:1,iname:banjo ,rid:2,rname:kapow,rtype:R,fstart:100,fend:250,fundamental:0,audiofile:,audiopath: 
frequency,fid:3,iid:1,iname:banjo ,rid:3,rname:whump,rtype:R,fstart:1000,fend:2000,fundamental:0,audiofile:,audiopath: 
frequency,fid:4,iid:2,iname:piano,rid:1,rname:crump,rtype:R,fstart:1000,fend:1500,fundamental:0,audiofile:,audiopath: 
frequency,fid:5,iid:2,iname:piano,rid:2,rname:kapow,rtype:R,fstart:2000,fend:3000,fundamental:1,audiofile:,audiopath: 
frequency,fid:6,iid:2,iname:piano,rid:3,rname:whump,rtype:R,fstart:4000,fend:5000,fundamental:0,audiofile:,audiopath: 
frequencyorder,position:0,fid:1
frequencyorder,position:1,fid:2
frequencyorder,position:2,fid:3
frequencyorder,position:3,fid:4
frequencyorder,position:4,fid:5
frequencyorder,position:5,fid:6
statistic,type:FlashType.frequency,fid:1,iid:1,rid:1,presented:0,correct:0
statistic,type:FlashType.frequency,fid:2,iid:1,rid:2,presented:0,correct:0
statistic,type:FlashType.frequency,fid:3,iid:1,rid:3,presented:0,correct:0
statistic,type:FlashType.frequency,fid:4,iid:2,rid:1,presented:0,correct:0
statistic,type:FlashType.frequency,fid:5,iid:2,rid:2,presented:0,correct:0
statistic,type:FlashType.frequency,fid:6,iid:2,rid:3,presented:0,correct:0
statistic,type:FlashType.ranges,fid:1,iid:1,rid:1,presented:0,correct:0
statistic,type:FlashType.ranges,fid:2,iid:1,rid:2,presented:0,correct:0
statistic,type:FlashType.ranges,fid:3,iid:1,rid:3,presented:0,correct:0
statistic,type:FlashType.ranges,fid:4,iid:2,rid:1,presented:0,correct:0
statistic,type:FlashType.ranges,fid:5,iid:2,rid:2,presented:0,correct:0
statistic,type:FlashType.ranges,fid:6,iid:2,rid:3,presented:0,correct:0
statistic,type:FlashType.fundamentals,fid:1,iid:1,rid:1,presented:0,correct:0
statistic,type:FlashType.fundamentals,fid:2,iid:1,rid:2,presented:0,correct:0
statistic,type:FlashType.fundamentals,fid:3,iid:1,rid:3,presented:0,correct:0
statistic,type:FlashType.fundamentals,fid:4,iid:2,rid:1,presented:0,correct:0
statistic,type:FlashType.fundamentals,fid:5,iid:2,rid:2,presented:0,correct:0
statistic,type:FlashType.fundamentals,fid:6,iid:2,rid:3,presented:0,correct:0
statistic,type:FlashType.sounds,fid:1,iid:1,rid:1,presented:0,correct:0
statistic,type:FlashType.sounds,fid:2,iid:1,rid:2,presented:0,correct:0
statistic,type:FlashType.sounds,fid:3,iid:1,rid:3,presented:0,correct:0
statistic,type:FlashType.sounds,fid:4,iid:2,rid:1,presented:0,correct:0
statistic,type:FlashType.sounds,fid:5,iid:2,rid:2,presented:0,correct:0
statistic,type:FlashType.sounds,fid:6,iid:2,rid:3,presented:0,correct:0
setting,name:colourOneEnabled,setting:false
setting,name:colourOne,setting:#fffff59d
setting,name:colourTwoEnabled,setting:false
setting,name:colourTwo,setting:#ff9dffb1
setting,name:fontColourEnabled,setting:false
setting,name:fontColour,setting:#ff000000
setting,name:fundamentalColourEnabled,setting:false
setting,name:fundamentalColour,setting:#ff4caf50
setting,name:disabledColourEnabled,setting:false
setting,name:disabledColour,setting:#ff9e9e9e
setting,name:themeMode,setting:ThemeMode.dark
setting,name:leftHanded,setting:false

The import routine that reads this file uses readAsStringSync (I have the same issue if I use readAsLinesSync) as follows:

String fullName = result.files.first.path as String;
dynamic temp = File(fullName).readAsStringSync();
print('$temp');

The debug console output looks like this:

I/flutter ( 6499): instrument,id:1,name:banjo 
I/flutter ( 6499): instrument,id:2,name:piano 
I/flutter ( 6499): instrument,id:3,name:xylophone 
I/flutter ( 6499): range name,id:1,name:crump 
I/flutter ( 6499): range name,id:2,name:kapow 
I/flutter ( 6499): range name,id:3,name:whump 
I/flutter ( 6499): frequency,fid:1,iid:1,iname:banjo ,rid:1,rname:crump,rtype:R,fstart:30,fend:60,fundamental:1,audiofile:,audiopath: 
I/flutter ( 6499): frequency,fid:2,iid:1,iname:banjo ,rid:2,rname:kapow,rtype:R,fstart:100,fend:250,fundamental:0,audiofile:,audiopath: 
I/flutter ( 6499): frequency,fid:3,iid:1,iname:banjo ,rid:3,rname:whump,rtype:R,fstart:1000,fend:2000,fundamental:0,audiofile:,audiopath: 
I/flutter ( 6499): frequency,fid:4,iid:2,iname:piano,rid:1,rname:crump,rtype:R,fstart:1000,fend:1500,fundamental:0,audiofile:,audiopath: 
I/flutter ( 6499): frequency,fid:5,iid:2,iname:piano,rid:2,rname:kapow,rtype:R,fstart:2000,fend:3000,fundamental:1,audiofile:,audiopath: 
I/flutter ( 6499): frequency,fid:6,iid:2,iname:piano,rid:3,rname:whump,rtype:R,fstart:4000,fend:5000,fundamental:0,audiofile:,audiopath: 
I/flutter ( 6499): frequencyorder,position:0,fid:1 
I/flutter ( 6499): frequencyorder,position:1,fid:2 
I/flutter ( 6499): frequencyorder,position:2,fid:3 
I/flutter ( 6499): frequencyorder,position:3,fid:4 
I/flutter ( 6499): frequencyorder,position:4,fid:5 
I/flutter ( 6499): frequencyorder,position:5,fid:6 
I/flutter ( 6499): setting,name:colourOneEnabled,setting:false 
I/flutter ( 6499): setting,name:colourOne,setting:#fffff59d 
I/flutter ( 6499): setting,name:colourTwoEnabled,setting:false 
I/flutter ( 6499): setting,name:colourTwo,setting:#ff9dffb1 
I/flutter ( 6499): setting,name:fontColourEnabled,setting:false 
I/flutter ( 6499): setting,name:fontColour,setting:#ff000000 
I/flutter ( 6499): setting,name:fundamentalColourEnabled,setting:false 
I/flutter ( 6499): setting,name:fundamentalColour,setting:#ff4caf50 
I/flutter ( 6499): setting,name:disabledColourEnabled,setting:false 
I/flutter ( 6499): setting,name:disabledColour,setting:#ff9e9e9e 
I/flutter ( 6499): setting,name:themeMode,setting:ThemeMode.system 
I/flutter ( 6499): setting,name:leftHanded,setting:false

Note the missing “statistic” lines between the "frequencyorder" and "setting" lines.

I am running Flutter (Channel stable, 3.7.11, on Microsoft Windows [Version 10.0.22621.1555], locale en-GB).

Does anyone have any ideas why this is happening?

答案1

得分: 0

以下是翻译好的部分:

根据这里的帖子:https://stackoverflow.com/questions/50060648/special-characters-in-flutter,解决方案是将点转换为Unicode,然后导出字符串。当通过readAsString或readAsLines读取时,Unicode会自动转换回点。我的导出代码现在如下:

    Future<String> exportStatistics({required MyDatabase database}) async {
      String output = '';

      // 从数据库获取统计记录(Future)
      await DataStatistics.getAllStatistics(db: database).then((statistics) {
        for (StatRecord s in statistics) {
          output += 'statistic,';
          dynamic temp = s.type.toString().replaceAll('.', '\u002e');
          output += 'type:$temp,';
          output += 'fid:${s.id},';
          output += 'iid:${s.iid},';
          output += 'rid:${s.rid},';
          output += 'presented:${s.presented},';
          output += 'correct:${s.correct}\n';
        }
      });
      return output;
    }

这在测试中并不立即明显,因为我还了解到,至少在我的设置中,当我在物理连接的设备上测试应用时,需要在导入新文件之前清除应用程序的缓存。如果我不这样做,那么在更改导出例程、重新启动应用程序并重新导出数据到导出文件之后,应用程序似乎会导入文件的以前缓存版本。因此,看起来更改没有起作用,实际上已经生效。

英文:

As per the post here: https://stackoverflow.com/questions/50060648/special-characters-in-flutter, the solution is to convert the dot to unicode and then export the String. When this is read by readAsString or readAsLines, the unicode is converted back to a dot automatically. My export code now looks like this:

    Future&lt;String&gt; exportStatistics({required MyDatabase database}) async {
      String output = &#39;&#39;;

      // Get statistics records from the database (Future)
      await DataStatistics.getAllStatistics(db: database).then((statistics) {
        for (StatRecord s in statistics) {
          output += &#39;statistic,&#39;;
          dynamic temp = s.type.toString().replaceAll(&#39;.&#39;, &#39;\u002e&#39;);
          output += &#39;type:$temp,&#39;;
          output += &#39;fid:${s.id},&#39;;
          output += &#39;iid:${s.iid},&#39;;
          output += &#39;rid:${s.rid},&#39;;
          output += &#39;presented:${s.presented},&#39;;
          output += &#39;correct:${s.correct}\n&#39;;
        }
      });
      return output;
    }

This wasn't immediately obvious in testing because I have also learned that, on my setup at least, when I am testing the app on a physically attached device I needed to clear the cache on the app before importing the new file. If I don't do this, then the app seems to be importing a previously cached version of the file even after changing the export routine, restarting the app and re-exporting the data to the export file. Because of this, it looks like changes haven't worked when they have.

huangapple
  • 本文由 发表于 2023年4月17日 01:37:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/76029356.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定