Flutter数据序列化与反序列化插件message_pack_dart的使用

发布于 1周前 作者 zlyuanteng 来自 Flutter

Flutter数据序列化与反序列化插件message_pack_dart的使用

简介

messagePack_dart 是一个用于 Dart 和 Flutter 的 MessagePack 实现。MessagePack 是一种高效的二进制序列化格式,它可以在多种编程语言之间交换数据,类似于 JSON,但速度更快、体积更小。小整数可以编码为单个字节,短字符串也只需要额外一个字节。

安装

pubspec.yaml 文件中添加以下依赖:

dependencies:
  message_pack_dart: ^latest_version

然后运行 flutter pub get 来安装插件。

示例代码

以下是一个完整的示例,展示了如何使用 message_pack_dart 进行数据的序列化和反序列化。这个示例包括了对不同数据类型的测试,并比较了 JSON 和 MessagePack 的性能。

import 'dart:convert';
import 'dart:io';
import 'package:message_pack_dart/message_pack_dart.dart' as m2;

const int TIMES = 10000;

// 辗转相除法计算最大公约数
gcd(num a, num b) => b != 0 ? gcd(b, a % b) : a;

class Fraction {
  final num numerator;
  final num denominator;

  Fraction(this.numerator, this.denominator);

  // 化简分数
  Fraction reduce() {
    var cd = gcd(numerator, denominator);
    return Fraction(numerator / cd, denominator / cd);
  }

  // 交叉乘法
  Fraction cross(Fraction other) => Fraction(
      other.denominator * numerator, other.numerator * denominator);

  [@override](/user/override)
  String toString() => "${numerator}/${denominator}";

  // 返回比例字符串
  String toRatioString() => "${numerator}:${denominator}";
}

void main(List<String> args) async {
  print("预热...");
  for (var i = 0; i < TIMES; i++) {
    var jsonStr = json.encode({"hello": "world"});
    json.encode(json.decode(jsonStr));
  }

  if (args.contains("--savings")) {
    var numbers = [];
    for (var i = 1; i <= 100000; i++) {
      numbers.add(i);
    }

    // 比较 JSON 和 MessagePack 的字节数
    var jsonBytes = utf8.encode(json.encode(numbers)).length;
    var msgpack2Bytes = m2.serialize(numbers).length;
    print("JSON: ${jsonBytes} bytes, messagePack: ${msgpack2Bytes} bytes");
  }

  var objects = {
    "One": 1,
    "Five Hundred Thousand": 500000,
    "List of Small Integers": [1, 2, 3],
    "Simple Map": {"hello": "world"},
    "5.02817472928": 5.02817472928,
    "Multiple Type Map": {
      "String": "Hello World",
      "Integer": 1,
      "Double": 2.0154,
      "Array": const [1, 2, 3, "Hello"]
    },
    "Medium Data": {
      "/downstream/wemo/CoffeeMaker-1_0-221421S0000731/Brew_Age": [
        [1440366101049, -123881],
        [1440366102047, -123882],
        [1440366103049, -123883],
        [1440366104046, -123884],
        [1440366105062, -123885],
        [1440366106050, -123886],
        [1440366107046, -123887],
        [1440366108045, -123888],
        [1440366109036, -123889],
        [1440366110048, -123890],
        [1440366111047, -123891],
        [1440366112037, -123892],
        [1440366113048, -123893],
        [1440366114048, -123894],
        [1440366115046, -123895],
        [1440366116044, -123896],
        [1440366117045, -123897],
        [1440366118049, -123898],
        [1440366119046, -123899],
        [1440366120042, -123900],
        [1440366121047, -123901],
        [1440366122048, -123902],
        [1440366123046, -123903],
        [1440366124055, -123904],
        [1440366126059, -123906],
        [1440366127054, -123907],
        [1440366128047, -123908],
        [1440366129051, -123909],
        [1440366130051, -123910],
        [1440366131048, -123911],
        [1440366132050, -123912],
        [1440366133032, -123913],
        [1440366134045, -123914],
        [1440366135050, -123915],
        [1440366136049, -123916]
      ]
    }
  };

  bool markdown = false;
  if (args.contains("-m")) markdown = true;

  if (args.contains("-u")) {
    if (markdown) {
      print("反序列化\n===");
    } else {
      print("=== 反序列化 ===");
    }

    for (var key in objects.keys) {
      testObjectDecode(key, objects[key], markdown);
    }
  } else if (args.contains("-a")) {
    if (markdown) {
      print("序列化\n===");
    } else {
      print("=== 序列化 ===");
    }
    for (var key in objects.keys) {
      testObjectEncode(key, objects[key], markdown);
    }
    if (markdown) {
      print("反序列化\n===");
    } else {
      print("=== 反序列化 ===");
    }
    for (var key in objects.keys) {
      testObjectDecode(key, objects[key], markdown);
    }
  } else {
    if (markdown) {
      print("序列化\n===");
    } else {
      print("=== 序列化 ===");
    }

    for (var key in objects.keys) {
      testObjectEncode(key, objects[key], markdown);
    }
  }
}

void testObjectDecode(String desc, input, bool markdown) {
  if (markdown) {
    print('$desc\n---');
  } else {
    print("${desc}:");
  }
  var packedJson = json.encode(input);

  var watch = Stopwatch();
  var watchTotal = Stopwatch();
  var times = [];
  watchTotal.start();
  for (var i = 1; i <= TIMES; i++) {
    watch.reset();
    watch.start();
    json.decode(packedJson);
    watch.stop();
    times.add(watch.elapsedMicroseconds);
  }
  var totalTime = watchTotal.elapsedMicroseconds;
  var avgTime = totalTime / TIMES;
  times.sort((a, b) => a.compareTo(b));

  if (!markdown) {
    print("  JSON:");
    print("    总时间: $totalTime 微秒 (${totalTime / 1000}ms)");
    print("    平均时间: $avgTime 微秒 (${avgTime / 1000}ms)");
    print("    最长时间: ${times.last} 微秒 (${times.last / 1000}ms)");
    print("    最短时间: ${times.first} 微秒 (${times.first / 1000}ms)");
  }
  var jTotal = totalTime;
  var jAvg = avgTime;
  var jLong = times.last;
  var jShort = times.first;

  watch.reset();
  times.clear();
  watchTotal.reset();
  for (var i = 1; i <= TIMES; i++) {
    watch.reset();
    watch.start();
    m2.deserialize(m2.serialize(input));
    watch.stop();
    times.add(watch.elapsedMicroseconds);
  }
  totalTime = watchTotal.elapsedMicroseconds;
  avgTime = totalTime / TIMES;
  times.sort((a, b) => a.compareTo(b));
  if (!markdown) {
    print("  MsgPack2:");
    print("    总时间: ${totalTime} 微秒 (${totalTime / 1000}ms)");
    print("    平均时间: ${avgTime} 微秒 (${avgTime / 1000}ms)");
    print("    最长时间: ${times.last} 微秒 (${times.last / 1000}ms)");
    print("    最短时间: ${times.first} 微秒 (${times.first / 1000}ms)");
  }
  var nTotal = totalTime;
  var nAvg = avgTime;
  var nLong = times.last;
  var nShort = times.first;

  if (markdown) {
    print("时间 | JSON | MsgPack2 | msgpack_dart |");
    print("-----|------|----------|--------------|");
    print("总时间 | $jTotal μs (${jTotal / 1000}ms) | " +
        "$nTotal μs (${nTotal / 1000}ms) |" +
        "$n2Total μs (${n2Total / 1000}ms)");
    print("平均时间 | $jAvg μs (${jAvg / 1000}ms) | " +
        "$nAvg μs (${nAvg / 1000}ms) |" +
        "$n2Avg μs (${n2Avg / 1000}ms)");
    print("最长时间 | $jLong μs (${jLong / 1000}ms) | " +
        "$nLong μs (${nLong / 1000}ms) |" +
        "$n2Long μs (${n2Long / 1000}ms)");
    print("最短时间 | $jShort μs (${jShort / 1000}ms) | " +
        "$nShort μs (${nShort / 1000}ms) |" +
        "$n2Short μs (${n2Short / 1000}ms)");
  }

  var bestAvg = n2Avg;
  String fastest = "msgpack_dart";
  if (nAvg < bestAvg) {
    bestAvg = nAvg;
    fastest = "MsgPack2";
  }
  if (jAvg < bestAvg) {
    bestAvg = jAvg;
    fastest = "JSON";
  }

  if (markdown) {
    print("最快 | $fastest\n");
  } else {
    print("  $fastest was fastest");
  }
}

void testObjectEncode(String desc, input, bool markdown) {
  if (markdown) {
    print("$desc\n---");
  } else {
    print("${desc}:");
  }
  var watch = Stopwatch();
  var watchTotal = Stopwatch();
  var times = [];

  watchTotal.start();
  int size = utf8.encode(json.encode(input)).length;
  for (var i = 1; i <= TIMES; i++) {
    watch.reset();
    watch.start();
    json.encode(input);
    watch.stop();
    times.add(watch.elapsedMicroseconds);
  }
  var totalTime = watchTotal.elapsedMicroseconds;
  var avgTime = totalTime / TIMES;
  times.sort((a, b) => a.compareTo(b));
  if (!markdown) {
    print("  JSON:");
    print("    总时间: $totalTime 微秒 (${totalTime / 1000}ms)");
    print("    平均时间: $avgTime 微秒 (${avgTime / 1000}ms)");
    print("    最长时间: ${times.last} 微秒 (${times.last / 1000}ms)");
    print("    最短时间: ${times.first} 微秒 (${times.first / 1000}ms)");
    print("    大小: ${size} 字节");
  }
  var jTotal = totalTime;
  var jAvg = avgTime;
  var jLong = times.last;
  var jShort = times.first;
  var jSize = size;

  watch.reset();
  times.clear();
  watchTotal.reset();
  for (var i = 1; i <= TIMES; i++) {
    watch.reset();
    watch.start();
    m2.serialize(input);
    watch.stop();
    times.add(watch.elapsedMicroseconds);
  }
  totalTime = watchTotal.elapsedMicroseconds;
  avgTime = totalTime / TIMES;
  times.sort((a, b) => a.compareTo(b));
  if (!markdown) {
    print("  MsgPack2:");
    print("    总时间: ${totalTime} 微秒 (${totalTime / 1000}ms)");
    print("    平均时间: ${avgTime} 微秒 (${avgTime / 1000}ms)");
    print("    最长时间: ${times.last} 微秒 (${times.last / 1000}ms)");
    print("    最短时间: ${times.first} 微秒 (${times.first / 1000}ms)");
    print("    大小: ${m2.serialize(input).length} 字节");
  }
  var nTotal = totalTime;
  var nAvg = avgTime;
  var nLong = times.last;
  var nShort = times.first;
  var nSize = m2.serialize(input).length;

  if (markdown) {
    print("时间 | JSON | MsgPack2 | msgpack_dart |");
    print("-----|------|---------|--------------|");
    print("总时间 | $jTotal μs (${jTotal / 1000}ms) | " +
        "$nTotal μs (${nTotal / 1000}ms) | " +
        "$n2Total μs (${n2Total / 1000}ms)");
    print("平均时间 | $jAvg μs (${jAvg / 1000}ms) | " +
        "$nAvg μs (${nAvg / 1000}ms) | " +
        "$n2Avg μs (${n2Avg / 1000}ms)");
    print("最长时间 | $jLong μs (${jLong / 1000}ms) | " +
        "$nLong μs (${nLong / 1000}ms) | " +
        "$n2Long μs (${n2Long / 1000}ms)");
    print("最短时间 | $jShort μs (${jShort / 1000}ms) | " +
        "$nShort μs (${nShort / 1000}ms) | " +
        "$n2Short μs (${n2Short / 1000}ms)");
    print("大小 | $jSize 字节 | $nSize 字节 | $n2Size 字节");
  }

  var bestAvg = n2Avg;
  String fastest = "msgpack_dart";
  if (nAvg < bestAvg) {
    bestAvg = nAvg;
    fastest = "MsgPack2";
  }
  if (jAvg < bestAvg) {
    bestAvg = jAvg;
    fastest = "JSON";
  }

  if (markdown) {
    print("最快 | $fastest\n");
  } else {
    print("  $fastest was fastest");
  }
}

更多关于Flutter数据序列化与反序列化插件message_pack_dart的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter数据序列化与反序列化插件message_pack_dart的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter应用中,message_pack_dart 是一个用于数据序列化和反序列化的插件,它基于 MessagePack 格式,这是一种高效的二进制序列化格式。使用 message_pack_dart 可以方便地在 Flutter 应用中传输和存储数据。

以下是一个简单的示例,展示如何在 Flutter 中使用 message_pack_dart 插件进行数据序列化和反序列化。

首先,确保在 pubspec.yaml 文件中添加 message_pack_dart 依赖:

dependencies:
  flutter:
    sdk: flutter
  message_pack_dart: ^2.0.0  # 请检查最新版本号

然后,运行 flutter pub get 来获取依赖。

接下来,编写 Dart 代码来演示序列化和反序列化过程:

import 'package:flutter/material.dart';
import 'package:message_pack_dart/message_pack.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('MessagePack Dart Demo'),
        ),
        body: Center(
          child: MyWidget(),
        ),
      ),
    );
  }
}

class MyWidget extends StatefulWidget {
  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  String serializedData = '';
  Map<String, dynamic> deserializedData = {};

  void serializeData() {
    // 要序列化的数据
    Map<String, dynamic> data = {
      'name': 'Alice',
      'age': 30,
      'isStudent': false,
      'scores': [95, 88, 92],
    };

    // 使用 MessagePack 序列化数据
    var packer = MessagePack();
    Uint8List packedData = packer.pack(data);

    // 将序列化后的数据转换为 Base64 字符串以便显示
    serializedData = base64Encode(packedData);

    // 更新界面
    setState(() {});
  }

  void deserializeData() {
    if (serializedData.isEmpty) {
      return;
    }

    // 将 Base64 字符串转换回 Uint8List
    Uint8List packedData = base64Decode(serializedData);

    // 使用 MessagePack 反序列化数据
    var unpacker = MessagePack();
    deserializedData = unpacker.unpack(packedData) as Map<String, dynamic>;

    // 更新界面
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        ElevatedButton(
          onPressed: serializeData,
          child: Text('Serialize Data'),
        ),
        SizedBox(height: 20),
        ElevatedButton(
          onPressed: deserializeData,
          child: Text('Deserialize Data'),
        ),
        SizedBox(height: 40),
        Text('Serialized Data (Base64):'),
        Text(serializedData),
        SizedBox(height: 20),
        Text('Deserialized Data:'),
        if (deserializedData.isNotEmpty)
          Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              Text('Name: ${deserializedData['name']}'),
              Text('Age: ${deserializedData['age']}'),
              Text('Is Student: ${deserializedData['isStudent']}'),
              Text('Scores: ${deserializedData['scores'].join(', ')}'),
            ],
          ),
      ],
    );
  }
}

在这个示例中,我们创建了一个简单的 Flutter 应用,其中包含一个用于序列化和反序列化数据的界面。我们定义了两个方法 serializeDatadeserializeData

  • serializeData 方法将一个 Map 对象序列化为二进制数据,并将其转换为 Base64 字符串以便显示。
  • deserializeData 方法将 Base64 字符串转换回二进制数据,并使用 MessagePack 反序列化回原始的 Map 对象。

运行这个应用,点击“Serialize Data”按钮将数据显示为序列化后的 Base64 字符串,点击“Deserialize Data”按钮将显示反序列化后的数据。

回到顶部