项目场景:

近期Joe大叔因工作需求,小程序需要实现打开图片文件和PDF功能。当然,被打开的文件是需要增加缓存策略的,要不然每次打开一个6M的PDF文件都去服务端下载然后再打开,会严重影响到小程序迅速响应的用户体验。


问题描述:

那么在实现上述功能时,Joe大叔遇到了一个略显糟心的问题:小程序调用API下载并存储文件到本地后,无法根据本地文件列表确定当前文件是否已下载。

uni.getSavedFileList({success(res) {console.log('获取本地文件列表:\n',res)}
})
// 获取到的数据如下
// {createTime: 1628172373, filePath: "http://store/dleIyVcYMhBP1ec1df7ee3ab6c552f8bd4deff1d1264.jpeg", size: 288419}

原因分析:

现在本地文件列表也拿到了,为什么还不能得知当前文件是否已下载过呢?通过查看数据可以得知,保存好的每一个文件都被封装成了一个字典对象。其中 filePath 表示文件的本地路径,createTime 表示文件保存时的时间戳,size 表示文件的大小。首先把时间戳、文件大小排除,就只剩下文件路径。 但是,这个路径是有种编码格式的,也即它是随机的。下载同一个文件,所生成的本地路径都是不同的。那么,我们该如何解决这个问题呢?


解决方案:

Joe大叔在这里先行献丑了,解决方案分两步:(文末附有Github项目地址)

1、每当文件下载、保存成功后,以文件名为 key,保存文件的路径为 value,包装成字典对象并 push 到一个文件列表数组中。再使用 uni.setStorage 把文件列表数组缓存至本地。

                // 没有保存过文件,就开启下载任务uni.showLoading({title:'正在下载...',mask:true})var that = this;uni.downloadFile({url:this.imagePath,success(res) {if (res.statusCode === 200) {var tempFilePath = res.tempFilePath;uni.saveFile({tempFilePath:tempFilePath,success(res) {console.log('文件保存成功')var savedFilePath = res.savedFilePath;// 获取本地文件的文件信息uni.getSavedFileInfo({filePath:savedFilePath,success(res) {that.totalSizeStr = parseInt(res.size / 1024 / 1024) + ''}})getStorage(cachedFileKey).then((cachedArray) => {// 以文件名为key,文件保存的路径为value,组装成一个字典对象保存到数组,再把数组写入本地// 创建一个用于承载字典对象的数组var saveFileArray = [];// 先判断本地有无缓存的文件名、文件路径数组if (!!cachedArray && cachedArray.length > 0) {// 若存在则赋值给saveFileArraysaveFileArray = cachedArray} // 把字典装入数组中saveFileArray.push({fileKey: that.imagePath,filePath: savedFilePath})// 再把数组写入本地setStorage(cachedFileKey,saveFileArray).then(() => {that.isDownload = true;// 直接打开文件uni.previewImage({urls:[savedFilePath]})// 更新一下本地文件列表 fileListuni.getSavedFileList({success(res) {that.fileList = res.fileList}})})})}})}},fail(err) {uni.showToast({title:JSON.stringify(err),icon:'none',duration:1000 * 5})},complete() {uni.hideLoading()}})

当再次打开同一个文件地址时,首先使用 uni.getStorage 获取缓存的文件列表数组,再判断数组中是否已包含与当前文件名一致的 key 值。这就可以解决下载的文件无法标记的问题。

                // 先判断 fileList 是否为空,为空直接开启文件下载if (this.fileList.length === 0) {// 开启文件下载this.downloadFile()return;}// 再判断是否文件已经下载过getStorage(cachedFileKey).then((cachedArray) => {// 同样要判断 cachedArray 是否存在if (!!cachedArray && cachedArray.length > 0) {// 若存在则进行文件名与 fileKey 的比对var fileKeyArray = [];var fileKeyFilePathArray = [];var resultArray = [];cachedArray.map((item) => {fileKeyArray.push(item.fileKey)fileKeyFilePathArray.push(item)})// 这里使用 filter 函数是一个筛选小技巧,可以直接遍历得到需要的数据resultArray = fileKeyFilePathArray.filter((item) => {if (item.fileKey === this.imagePath) {return true} else {return false}})// 使用数组的 indexOf 方法来比对当前文件名if (fileKeyArray.indexOf(this.imagePath) > -1) {// > -1 表示比对成功,文件已下载,直接打开// 这里需要注意一下:如果是要打开图片,就使用 uni.previewImage// 如果要打开doc, xls, ppt, pdf, docx, xlsx, pptx,就使用 uni.openDocument// 因为我在这里使用的是jpg图片,所以就使用 uni.previewImageuni.showModal({title:'检测到您已下载过此文件,是否直接打开?',success(res) {if (res.confirm) {uni.previewImage({urls:[resultArray[0].filePath],fail(err) {console.log(err)}})}}})} else {// 比对不成功,则直接开启文件下载this.downloadFile()}}})

2、经过Joe大叔实测,小程序文件下载是有上限的,大概100M,本地文件总大小达到或超过这个数之后,就无法下载成功,大家可以亲自试验下。

所以,我们还需要做一个文件缓存策略,怎么做呢?很简单,前面我们已经可以获取到本地缓存文件的大小了,只要遍历出来再进行累加,就能得出总大小。这里要注意一下的是,默认大小是以字节为单位的,所以转换为M的话是需要再除以 1024 * 1024 的。

                var that = this;uni.getSavedFileList({success(res) {var fileList = res.fileList;that.fileList = res.fileList;// 判断 fileList 不为空,计算一下文件总大小,如果超限需要删除部分文件以挪出空间if (fileList.length === 0) {return;}var totalSize = 0;// 设置文件缓存限额为50Mvar sizeLimit = 50 * 1024 * 1024;fileList.map((item) => {totalSize += item.size})that.totalSizeStr = parseInt(totalSize / 1024 / 1024) + ''// 判断总大小是否超限if (totalSize >= sizeLimit) {// 执行文件删除操作,具体删除几个文件可以自己调整uni.removeSavedFile({filePath:fileList[0].filePath,success() {}})}}})

Joe大叔对文件总大小设置了50M的限额,当然,大家可以根据实际项目需要进行调整。当总大小超过50M时,需要执行 uni.removeSavedFile 来删除本地保存的文件,以挪出空间。

至此,我们就解决了小程序文件缓存问题,最后再献上对 uni.getStorage、uni.setStorage 的 Promise 封装吧。

/*
这里说下为什么要把 uni.getStorage 和 uni.setStorage 使用 Promise 封装一下:因为封装后用起来爽啊~ uni.getStorage、uni.setStorage 直接使用不适合实际开发,一堆 success、fail 回调
*/ export const getStorage = function(key) {return new Promise((resolve, reject) => {uni.getStorage({key:key,success(res) {resolve(res.data)},fail() {resolve(null)}})})
}export const setStorage = function(key, data) {return new Promise((resolve, reject) => {uni.setStorage({key:key,data:data,success() {resolve(true)},fail() {resolve(false)}})})
}export const cachedFileKey = 'cachedFileKey'

本期Joe大叔有关小程序文件缓存问题的解决方案就在此告一段落了,很感谢能坚持看完这篇文章的朋友们,我们下期再见!

附件:https://github.com/zoeyzhong520/dataDownloadProject

小程序如何解决文件缓存问题?相关推荐

  1. uniapp 微信小程序开发 解决旧版本缓存

    1.uniapp 微信小程序如何解决旧版本缓存问题 在小程序发布新版本后,小程序端是异步更新,新版本覆盖较慢.如果用户之前已经打开过小程序,通过 热启动 再进入小程序时,可能访问的还是旧版本,需要一段 ...

  2. 微信小程序 本地mysql_微信小程序系列之使用缓存在本地模拟服务器数据库

    微信小程序系列之使用缓存在本地模拟服务器数据库 现在将data.js这个文件视作是本地数据库的初始化数据,要做的第一件事就是讲这些初始化数据装进缓存中,以形成数据库的初始化数据 整个应用程序的生命周期 ...

  3. 小程序性能优化——文件的本地存储10M优化算法

    小程序文件的本地存储优化 优化原因! 众所周知,微信将小程序的本地文件存储空间限制为10M,导致我们在调用wx.saveFile()接口存储临时文件时,存着存着,就超过10M了.那该怎么办呢? 肯定是 ...

  4. 微信小程序如何导入文件的一种方法

    微信小程序如何导入文件的一种方法,前三条才是有用的信息 1 环境 2 当你看到好的demo想在自己的小程序试试的时候 3 解决方式,进入本地文件夹直接复制 新的改变 功能快捷键 合理的创建标题,有助于 ...

  5. 微信小程序上传文件400

    微信小程序上传文件400 直接上示例问题代码 将请求头添加上Host即可解决 直接上示例问题代码 wx.uploadFile({url: 'https://' + domain + '/post/up ...

  6. 微信小程序+SpringBoot实现文件上传与下载

    微信小程序+SpringBoot实现文件上传与下载 1.文件上传 1.1 后端部分 1.1.1 引入Apache Commons FIleUpload组件依赖 1.1.2 设置上传文件大小限制 1.1 ...

  7. 微信小程序下载保存文件

    前言 总是有需求想在微信小程序里面做下载文件并保存的功能,所以自己整理了一下小程序涉及到下载api,大致理了下在小程序里面下载的流程和解决方案. 一.涉及api 1.wx.saveFile() ​ 文 ...

  8. 微信小程序PHP文件建在哪里,微信小程序解析H5文件方法

    经常有网友问怎么让微信小程序解析H5文件或者类似封装H5网页到APP里面?我一开始觉得这是不可能的,因为官方的解答是这样的: 每一个小程序页面是由同路径下同名的四个不同后缀文件的组成,如:index. ...

  9. java实现音频播放小程序_微信小程序实现音频文件播放进度的实例代码

    问题描述 在微信小程序中经常会用到控制文件播放的滑块,通过滑块可控制音频播放进度,下面即用代码实现. 解决方案 首先用.wxml与 .wmss 代码实现进度条的效果,再通过 .js 文件控制进度条的进 ...

最新文章

  1. 数据库事务的四大特性和隔离级别
  2. LeetCode 264. Ugly Number II--C++,Python解法
  3. 成都网络推广告诉大家网站抓取量要如何解决?
  4. 线性代数---线性方程组
  5. Java核心类库篇6——IO
  6. hadoop--完全分布式运行模式
  7. vfp报表纸张设置_VFP 9.0中实现多种自定义纸张格式的报表打印
  8. IView的Form表单自定义验证需注意事项
  9. 计算机网络实验题教程推介,计算机网络实验教程从原理到实践(附光盘)
  10. 2019-08-12 计划与安排
  11. 寻宝,大冒险!CSP202206-2
  12. Linux修改http为https访问
  13. IDM6.39序列号,亲测可用
  14. HDU - 3966(树链剖分)
  15. 营销:uplift模型
  16. 中国石油大学(北京)-《机器人设计》第一阶段在线作业
  17. Gym101194F-Mr. Panda and Fantastic Beasts
  18. 计算机替换规定文字颜色,改Windows系统字体颜色的方法
  19. 微信朋友圈图片显示缩放
  20. 主从概念以及主从的相关知识

热门文章

  1. 物联网时代之核心 论人工智能未来发展趋势
  2. Exchange 2013使用的一些细节
  3. 太闲则别念窃生,太忙则真性不现
  4. 学习笔记(01):SAS数据分析:从入门到企业实战-SAS PROC步骤I-2
  5. QQ云控引流 为您定制营销推广方案
  6. 这款全网热评的无线路由器,到底有什么特别?
  7. 旅游风景区`web大作业 静态网页
  8. import as在python_python import as教程
  9. Zend Framework 快速开始
  10. 利用FFmpeg和OpenGL ES 实现 3D 全景播放器