【问题标题】:Flutter dart export hive saved data to file to retrieve laterFlutter dart 将 hive 保存的数据导出到文件以供以后检索
【发布时间】:2021-08-24 07:34:03
【问题描述】:

我正在开发一个条形码应用程序并将数据保存到 hive。我需要知道的是有一种方法可以将保存的配置单元数据库导出到备份文件,并且能够在应用程序崩溃或手机丢失时检索它。这是为了盲人访问。想要将数据导出到我可以保存到我的电脑中进行存储的文件中,如果发生某些事情,我不必再次扫描所有产品来构建数据库。如果 hive 不能做到这一点,有人可以向我指出 Flutter dart 数据库可以做到这一点的方向。谢谢

好的,答案对我不起作用。这是我的模型文件的副本

    import 'package:hive/hive.dart';

    part 'product.g.dart';
    @HiveType(typeId: 0)
    class Product extends HiveObject{
      @HiveField(0)
      String itemName;
      @HiveField(1)
      String barCode;
      @HiveField(2)
      String bcType;

      Product(this.itemName, this.barCode, this.bcType);
    }

然后我打电话给我的盒子 var box = Hive.box('products');

如何将其编码为 json 以保存?

我用下一个

    Future<File> _createBackupFile() async {
      /// This example uses the OS temp directory

文件备份文件 = File('${Directory.systemTemp.path}/backup_barcode.json');

      try {
        /// barcodeBox is the [Box] object from the Hive package, usually exposed inside a [ValueListenableBuilder] or via [Hive.box()]
    var barcodeBox = Hive.box<Product>('products');
       backupFile = await backupFile.writeAsString(jsonEncode(barcodeBox.values));

        return backupFile;
      } catch (e) {
        // TODO: handle exception
    print(e);
      }
    }

【问题讨论】:

    标签: flutter dart flutter-hive


    【解决方案1】:

    据我所知,没有“开箱即用”的解决方案。这在很大程度上取决于您想要如何做到这一点的用例(因为有很多方法)。有关我如何为我的应用程序执行此操作的完整示例,您可以在此处查看: https://github.com/Kounex/obs_blade/blob/master/lib/views/settings/logs/log_detail/log_detail.dart(我使用了 share 包以便轻松导出它 - 但这不是必需的)

    Flutter 也有自己的文件读写文档 (https://flutter.dev/docs/cookbook/persistence/reading-writing-files) - 我将添加一些信息来完善它:

    存放地点


    首先我们必须考虑将“备份文件”存储在哪里。 Flutter 自己公开了您可以使用的公共路径(此外,path_provider 包为您提供了更大的灵活性)。如果您希望此备份文件是临时的,例如可以使用:

    Directory.systemTemp;
    

    文档说明:“这是操作系统提供的用于在其中创建临时文件和目录的目录。” 操作系统会确保在不同的场合删除它们,这样你就没有担心它。您还可以在此临时目录中创建其他目录以使其更易于区分,例如:

    Directory.systemTemp.createTemp('my_app');
    

    重要提示:这适用于非敏感数据。如果您正在处理的任何内容都包含敏感数据(如姓名、地址等),您必须确保数据安全/数据隐私。在这种情况下,我会使用前面提到的 path_provider 包,并在文档目录 (getApplicationDocumentsDirectory()) 中创建这些文件,并确保在使用/导出后立即删除它们。即使加密内容也可能是一个好主意 - 但我不会在这里深入研究。

    文件管理


    一旦我们知道文件的存储位置,我们只需要创建它们。前面的 Flutter 文档的第 3 章和第 4 章准确地说明了如何做到这一点,所以我宁愿专注于 what 来写。

    组合数据的一种常见且非常方便的方法是 JSON。 Flutter 也有这方面的文档:https://flutter.dev/docs/development/data-and-backend/json

    由于您使用的是 Hive,您可能已经有代表框中条目的类,您可以轻松地添加 toJson() 函数,在其中返回 Map&lt;String, dynamic&gt;(如文档中所示),您可以使用它来最后将需要的信息写入文件。

    根据您的 Hive 类,这是如何在 otder 中对其进行调整以正确序列化它:

    import 'package:hive/hive.dart';
    
    part 'product.g.dart';
    
    @HiveType(typeId: 0)
    class Product extends HiveObject{
      @HiveField(0)
      String itemName;
    
      @HiveField(1)
      String barCode;
    
      @HiveField(2)
      String bcType;
    
      Product(this.itemName, this.barCode, this.bcType);
    
      /// This function will automatically be used by the [jsonEncode()] function internally
      Map<String, dynamic> toJson() => {
        'itemName': this.itemName,
        'barCode': this.barCode,
        'bcType': this.bcType,
      }
    }
    

    一个小的示例实现可能如下所示:

    Future<File?> _createBackupFile() async {
      /// This example uses the OS temp directory
      File backupFile = File('${Directory.systemTemp.path}/backup_barcode.json');
    
      try {
        /// barcodeBox is the [Box] object from the Hive package, usually exposed inside a [ValueListenableBuilder] or via [Hive.box()]
        backupFile = await backupFile.writeAsString(jsonEncode(barcodeBox.values));
    
        return backupFile;
      } catch (e) {
        // TODO: handle exception
      }
    }
    

    这会将 Hive 框的 JSON 表示形式保存在临时 OS 目录中。您可以将目录换成最适合您的目录(在 Android 上,例如在外部存储上以便于访问)。

    现在您必须考虑如何以及何时触发它。例如,您可以通过触发按钮手动执行此操作,也可以在某个操作(如添加新条形码)后自动执行此操作,并选择一种适合您访问文件的方式。如前所述,将文件保存在易于访问的位置,如 Android 上的外部存储或使用共享包是可能的解决方案。

    【讨论】:

    • 我会试一试的。非常感谢您的详细解释。谢谢
    • 只是另一件事。如何导入保存的文件?
    • 导入保存的文件是什么意思?喜欢访问新创建的文件吗?这就是我将其存储在可访问的地方(例如外部存储)或使用共享包通过邮件或其他方式发送的意思!
    • 抛出此错误。但是今晚会花更多时间看看我是否可以尝试弄清楚。立即进行。
    • 我编辑了我的答案以添加必要的toJson() 函数以便工作 - 您可以在我提供的文档中阅读它
    【解决方案2】:

    Android 清单应包含以下内容:

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    
    <application
            android:requestLegacyExternalStorage="true"
    

    您需要this 包和this 包才能继续。

    现在是一种将数据备份到所需位置的方法:

    Future<void> createBackup() async {
    if (Hive.box<Product>('products').isEmpty) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('No Products Stored.')),
      );
      return;
    }
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('Creating backup...')),
    );
    Map<String, dynamic> map = Hive.box<Product>('products')
        .toMap()
        .map((key, value) => MapEntry(key.toString(), value));
    String json = jsonEncode(map);
    await Permission.storage.request();
    Directory dir = await _getDirectory();
    String formattedDate = DateTime.now()
        .toString()
        .replaceAll('.', '-')
        .replaceAll(' ', '-')
        .replaceAll(':', '-');
    String path = '${dir.path}$formattedDate.json';//Change .json to your desired file format(like .barbackup or .hive).
    File backupFile = File(path);
    await backupFile.writeAsString(json);
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('Backup saved in folder Barcodes')),
    );}
    
    
    Future<Directory> _getDirectory() async {
        const String pathExt = 'Barcodes/';//This is the name of the folder where the backup is stored
        Directory newDirectory = Directory('/storage/emulated/0/' + pathExt);//Change this to any desired location where the folder will be created
        if (await newDirectory.exists() == false) {
          return newDirectory.create(recursive: true);
        }
        return newDirectory;
      }
    

    最后,使用按钮调用此函数,它将以当前时间为名称以 JSON 格式保存备份。

    createBackup()
    

    在此之后将数据恢复回 Hive,

    Future<void> restoreBackup() async {
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('Restoring backup...')),
    );
    FilePickerResult? file = await FilePicker.platform.pickFiles(
      type: FileType.any,
    );
    if (file != null) {
      File files = File(file.files.single.path.toString());
      Hive.box<Product>('products').clear();
      Map<String, dynamic> map = jsonDecode(await files.readAsString());
      for (var i = 0; i < map.length; i++) {
        Product product = Product.fromJson(i.toString(), map);
        Hive.box<Product>('products').add(product);
      }
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Restored Successfully...')),
      );
    }
    }
    

    最后,使用按钮调用此函数,它将打开文件选择器,您可以在其中选择备份文件,它将删除现有数据并循环添加备份中的每个项目。

    restoreBackup()
    

    【讨论】:

    • 嗨。如果可以的话,请听一下 Product.fromJson(i.toString(), map) 函数
    猜你喜欢
    • 1970-01-01
    • 2013-06-23
    • 2019-10-02
    • 1970-01-01
    • 1970-01-01
    • 2020-07-09
    • 1970-01-01
    • 2012-01-29
    • 1970-01-01
    相关资源
    最近更新 更多