首页 > 解决方案 > 在离线桌面应用程序上显示 ZIP 存档中的图像的最有效方法是什么?

问题描述

我有一个离线Electron + React桌面应用程序,它不使用服务器来存储数据。情况如下:

用户可以创建一些文本数据并向其中添加任意数量的图像。当他们保存数据时,将ZIP创建具有以下结构的 a:

myFile.zip
  ├ main.json // Text data
  └ images
     ├ 00.jpg
     ├ 01.jpg
     ├ 02.jpg
     └ ...

如果他们想编辑数据,他们可以ZIP使用应用程序打开保存的数据。

我使用ADM-ZIP来阅读ZIP内容。打开后,我将JSON数据发送到,Redux因为我需要它们用于界面显示。但是,图像不会显示在读取存档的组件上,并且可以在应用程序的多个“页面”上(因此不同的组件)。我用一个带有道具并返回标签的Image组件来显示它们。我的问题是如何从档案中获取它们。nameimgsrc

所以这是我的问题:在给定上述情况下,获取图像数据的最有效方法是什么?ZIP


我目前在做什么:

当用户打开他们的文件时,我将其提取到ZIP一个临时文件夹中并从那里获取图像路径。临时文件夹仅在用户关闭文件时被删除,而不是在他们关闭应用程序时被删除(我不想更改此行为)。

// When opening the archive
const archive = new AdmZip('myFiles.zip');
archive.extractAllTo(tempFolderPath, true);

// Image component
const imageSrc = `${tempFolderPath}/images/${this.props.name}`;

问题:如果ZIP包含大量图像,用户必须在磁盘上有足够的空间才能正确提取它们。由于关闭应用程序时不一定会删除临时文件夹,这意味着将占用磁盘空间,直到他们关闭文件为止。


我尝试了什么:

  1. 将 ZIP 数据存储在内存中

    我尝试将打开的结果保存ZIP在道具中,然后在需要时从中获取图像数据:

    // When opening the archive
    const archive = new AdmZip('myFile.zip');
    this.props.saveArchive(archive); // Save in redux
    
    // Image component
    const imageData = this.props.archive.readFile(this.props.name);
    const imageSrc = URL.createObjectURL(new Blob([imageData], {type: "image/jpg"}));
    

    通过此过程,图像加载时间是可以接受的。

    问题:对于大型存档,将存档数据存储在内存中可能不利于性能(我认为?),我想我可以在那里存储多少是有限制的。

  2. 每次我必须显示图像时,再次使用 ADM-ZIP 打开 ZIP

    // Image component
    const archive = new AdmZip('myFile.zip');
    const imageData = archive.readFile(this.props.name);
    const imageSrc = URL.createObjectURL(new Blob([imageData], {type: "image/jpg"}));
    

    问题:性能不佳,当我在同一页面上有多个图像时非常慢。

  3. 在 IndexedDB 中存储图像缓冲区/Blob

    问题:它仍然存储在磁盘上,并且大小比提取的文件大得多。

  4. 使用不压缩数据的 ZIP

    问题:与压缩的ZIP.


我认为:

而不是 a ZIP,我试图找到一种可以充当非压缩存档并作为目录读取的文件类型,但我找不到类似的东西。我也尝试用香草创建一个自定义文件,Node.js但我担心我对文件系统 API的了解不足以做我想做的事。


我没有想法,所以欢迎任何建议。也许我没有看到最明显的方法......或者也许我目前正在做的事情并没有那么糟糕,我正在过度思考这个问题。

标签: javascriptnode.jsreactjselectronzip

解决方案


您所说的“最有效”是什么意思并不十分清楚。我会做出一些假设并根据它们提前做出回应。


缓存解决方案

基本上你已经做了什么。一次加载所有内容(提取到临时文件夹)非常有效,因为每当您需要重用某些内容时,不必再次完成最耗时的任务。加载资产/模块/等是一些重型应用程序的常见做法。在他们的启动。

Obs¹:由于您正在考虑磁盘空间不足是一个问题,因此如果您想坚持这一点,最好以编程方式处理这种情况并给用户一些提醒,因为几乎没有可用的存储空间是至关重要的。

TL;DR -起初是可消耗的,但后来更快地用于资产再利用

延迟加载

另一个非常常见的概念,基本上是“按需加载,只加载你需要的”。这是有效的,因为这种方法可确保您的应用程序仅加载运行所需的最小值,然后根据用户的要求加载内容。

Obs¹:它看起来很像你在第 2 次尝试中所做的事情。

TL;DR -启动时更快,运行时更慢

“智能”加载

这不是一个真实的名字,但它令人满意地描述了我的意思。基本上,专注于了解您的项目的目标并根据您的上下文混合以前的两种解决方案,这样您就可以在您的应用程序中实现最佳的整体性能,减少每种方法的权衡。

前任:

  • 延迟加载每个视图/页面的图像并保持有限大小的内存缓存

  • 在用户导航时在后台加载图像


现在,无论您的最终决定如何,都不应忽视以下注意事项:

  1. 内存的写入/读取速度总是比磁盘快
  2. 在许多包(包括 ADM-ZIP)中,部分解压缩(设置特定文件)是可能的,并且总是比解压缩所有文件更快,特别是在 ZIP 文件很大的情况下。
  3. 使用 IndexedDB 或 SQLite 等基于文件的自定义数据库可为大量文件和“智能”方法提供整体良好的结果,因为通过这些方法查询和组织数据更容易。
  4. 永远记住每个应用程序设计选择的原因,你越了解你为什么要做某事,你的最终结果就会越好。
  5. 说到话题 4,在我看来,在这种情况下,你确实有点想多了,但这并不是一件坏事,对如何以最好的方式做事有这种担忧真的很令人钦佩,我经常这样做即使没有必要,也有利于自我提升。

好吧,我写了很多:P

如果所有这些对您有所帮助,我将非常高兴。

祝你好运!

TL;DR - 根据您的问题没有封闭的答案,这在很大程度上取决于您的应用程序的上下文;你的一些尝试已经很不错了,但是努力理解可用性上下文以“智能”处理图像加载肯定会奖励你。


推荐阅读