Flutter:读取文件,解析为 JSON,然后转换为对象以使用点表示法

Flutter: Reading a file, parsing as JSON, then converting to an object in order to use dot notation

我正在尝试找到一种方法来读取以特定格式保存数据的文件,将其解析为 JSON,然后将其转换为对象,以便我可以使用点表示法。 这里的问题是使用点符号,因为它只是 returns null

CoreData.dart

import 'dart:convert';
import 'dart:io';
import 'dart:async';
import 'package:path_provider/path_provider.dart';

@proxy
class CoreObject {
  Map _data;

  CoreObject([String source]) {
    Map json = (source == null) ? new Map() : JSON.decode(source);
    _data = new Map.from(json);
    json.forEach((k, v) {
      print(k);
      _data[k] = v;
    });
  }

  static encode(List<CoreObject> list) {
    String result = "";
    for (CoreObject item in list) {
      result += "${item.toString()};";
    }
    return result;
  }

  @override toString() {
    print(this._data);
    return JSON.encode(this._data);
  }

  @override
  noSuchMethod(Invocation invocation) {
    var name = invocation.memberName.toString().replaceFirst('Symbol(\"', "");
    print("_data.keys ${_data.keys}");
    print("_data.values ${_data.values}");
    if (invocation.isGetter) {
      print("name ${name.replaceAll("\")", "")}");
      var ret = _data[name.replaceAll("\")", "")];
      print("ret $ret");
      print(ret.toString());
      return ret;
    }
    if (invocation.isSetter) {
      _data[name.replaceAll("=\")", "")] = invocation.positionalArguments.first;
    } else {
      super.noSuchMethod(invocation);
    }
  }
}

class Person extends CoreObject {
  Person([source]): super(source);
  @override noSuchMethod(Invocation invocation) {
    super.noSuchMethod(invocation);
  }
}

class CoreContainer {
  String _object;
  var returnNew;
  var path;

  _map(String source) {
    var result = [];
    for (var line in source.split(";")) {
      // print("line $line");
      if (line != "") result.add(returnNew(line));
    }
    print("result $result");
    return result;
  }

  encode(List<CoreObject> list) {
    // print("list $list");
    String result = "";
    list.forEach((CoreObject item) {
      // print("item ${item.toString()}");
      result += "${item};";
    });
    // print("result $result");
    return result;
  }

  CoreContainer(this._object, this.returnNew);

  Future<File> _getFile() async {
    String dir = path ?? (await getApplicationDocumentsDirectory()).path;
    this.path = dir;
    return new File('$dir/$_object.txt');
  }

  Future<List<CoreObject>> getAll() async {
    return _getFile().then((File file) {
      String contents = file.readAsStringSync();
      print("contents $contents");
      return this._map(contents);
    })
    .catchError((Error error) {
      print('error: $error');
      _getFile().then((File file) {
        file.writeAsStringSync("");
      });

      return [];
    });
  }

  save(List<CoreObject> data) async {
    _getFile().then((file) {
      try {
        file.writeAsStringSync(this.encode(data));
      }
      catch (error) {
        print("error: $error");
      }
    }).catchError((Error error) {
      print("error: $error");
    });
  }

  clear() async {
    return _getFile().then((file) {
      file.writeAsStringSync("");
    }).catchError((Error error) {
      print("error: $error");
    });
  }

  Future<List<CoreObject>> get(query) async {
    return this.getAll().then((List data) {
      data.retainWhere(query);
      return data;
    }).catchError((error) {
      print("error: $error");
    });    
  }

  Future<List<CoreObject>> remove(query) async {
    return this.getAll().then((List data) {
      // print(data);
      data.removeWhere(query);
      save(data);
      return data;
    }).catchError((error) {
      print("error: $error");
    });
  }

  Future<List<CoreObject>> add(obj) async {
    return this.getAll().then((data) {
      data.add(obj);
      return save(data).then(() {
        return data;
      })
      .catchError((Error error) {
        throw error;
      });
    }).catchError((Error error) {
      print("error: $error");
    });
  }

}

使用它:

CoreContainer corePerson = new CoreContainer("Person", (source) => new Person(source));

corePerson.getAll().then((List<CoreObject> array) {
  var tempItems = [];
  var i = 0;
  print("array $array");
  while (i < array.length) {
    Person person = array[i];
    print(person); //{"name":"<whatever 'i' is>"}
    print(person.name); //null
    tempItems.add(new ListTile(
      title: new Text("$i"),
      subtitle: new Text("${person.name}"),
    ));
    i++;
  }
  print(tempItems.length);
  count = tempItems.length;
  setState(() {
    items = tempItems;
  });
}).catchError((Error error) {
  print("error: $error, ${error.stackTrace}");
});

由于大量 print 调试,代码难以阅读。

但我想您需要一种方法将 JSON 数据转换为 Dart class。

您应该使用像 jaguar_serializer 这样的库来完成这项工作。

https://pub.dartlang.org/packages/jaguar_serializer

Dart 不像动态语言(Python、JavaScript)那样使用 dot 表示法。例如,在 Python 和 JavaScript 中,每个对象 实际上 内部是一个 HashMap,而 . 实际上是 属性 姓名:

a.bar // Loosely the same as a.lookup('bar')

Python/JS 虚拟机虽然可以 "see" a.bar 在类似 class 的对象 a 上像 属性 一样使用,并优化它以使用真正的 property/field 访问 - 这是 JIT(即时编译器)"optimization" 阶段的一部分。

正是这样的特性使得提前编译 Python 或 JS 几乎不可能 - 它们需要运行时配置文件信息来生成快速代码。 Dart(特别是 Dart 2.0)正在实现一个 sound 类型系统,其中 a.bar,当 a 已知时,always 属性 访问器,而不是哈希查找。

这意味着在运行时您不能采用任意哈希映射并强制它像对象一样工作,这就是为什么您的代码看起来很笨拙的原因。如果您 需要 带有 . 符号的类型化对象,我建议使用代码生成;如果不需要,我建议使用 HashMap []

还检查 答案,例如 json -> dart class 映射的基本方法。