在开发小程序预览PDF,docx的功能中,用到了小程序了wx.downloadFile,wx.openDocument,其原理是downloadFile下载来的临时文件其名字无法自定义,导致wx.openDocument调用时其标题就是文件名是临时导致的
问题
相关API
代码
wx.downloadFile({
url:"https://xxxxxx.pdf",
success(res){
console.log(res)
let data = res.tempFilePath;
wx.openDocument({
filePath:data,
fileType:'pdf'
})
}
})
解决方案
我们需要FileSystemManager 全局管理器,借助这个管理器提供的rename 重命名这个API将临时文件改名。但小程序的文件系统有规定读写权限,根椐这个表我们可以发现我们不能对临时文件进入写入权限,只有本地缓存文件才能写入。
文件系统
文件系统是小程序提供的一套以小程序和用户维度隔离的存储以及一套相应的管理接口。通过 wx.getFileSystemManager() 可以获取到全局唯一的文件系统管理器,所有文件系统的管理操作通过 FileSystemManager 来调用。
var fs = wx.getFileSystemManager()
文件主要分为两大类:
- 代码包文件:代码包文件指的是在项目目录中添加的文件。
- 本地文件:通过调用接口本地产生,或通过网络下载下来,存储到本地的文件。
其中本地文件又分为三种:
- 本地临时文件:临时产生,随时会被回收的文件。不限制存储大小。
- 本地缓存文件:小程序通过接口把本地临时文件缓存后产生的文件,不能自定义目录和文件名。跟本地用户文件共计,普通小程序最多可存储 10MB,游戏类目的小程序最多可存储 50MB。
- 本地用户文件:小程序通过接口把本地临时文件缓存后产生的文件,允许自定义目录和文件名。跟本地缓存文件共计,普通小程序最多可存储 10MB,游戏类目的小程序最多可存储 50MB。
接口、组件 | 读 | 写 |
---|---|---|
代码包文件 | 有 | 无 |
本地临时文件 | 有 | 无 |
本地缓存文件 | 有 | 无 |
本地用户文件 | 有 | 有 |
本地用户文件
本地用户文件是从 1.7.0 版本开始新增的概念。我们提供了一个用户文件目录给开发者,开发者对这个目录有完全自由的读写权限。通过 wx.env.USER_DATA_PATH 可以获取到这个目录的路径
由这个微信文件系统我们要实现这个标题跟PDF一致需要将我们downloadFile的文件转变成本地用户文件再调用getFileSystemManager().rename实现
//获取文件后缀 不止PDF也有docx;需要动态处理 借助getType
let type = this.getType(url);
let fs = wx.getFileSystemManager()
// url为文件URL, name为文件名
//downloadFile 运用 filePath 指定文件下载后存储的路径 (本地路径) 即我们要用到 wx.env.USER_DATA_PATH 创建路径和临时文件tem.pdf然后进行改名
wx.downloadFile({
url: url,
filePath: wx.env.USER_DATA_PATH + `/tem${type}`,
success: function (res) {
if (res.statusCode === 200) {
let filePath = res.tempFilePath;
fs.rename({
oldPath: wx.env.USER_DATA_PATH + `/tem${type}`,
newPath: wx.env.USER_DATA_PATH + `/${name}${type}`,
success: function (res) {
//存诸文件名为我们清除缓存(本地用户文件最多10M,因此需要解决,避免占用存诸)
let delectFile = wx.getStorageSync('filePath', delectFile) ? wx.getStorageSync('filePath', delectFile):[];
delectFile = [...delectFile, wx.env.USER_DATA_PATH + `/${name}${type}`]
wx.setStorageSync('filePath', delectFile)
//打开文档
wx.openDocument({
filePath: wx.env.USER_DATA_PATH + `/${name}${type}`,
success: function (res) {
console.log('打开文档成功')
},
fail: function (res) {
wx.showToast({
title: 'fail',
icon: 'none'
})
}
})
}, fail: function (res) {
wx.showToast({
title: '文件重命名失败',
icon: 'none'
})
}
})
}
},
fail: function (res) {
console.log('fail')
console.log(res)
},
})
后续优化代码 好像不用rename这个方法了可以,感觉上面代码多余了 O(∩_∩)O哈!
//获取文件后缀 不止PDF也有docx;需要动态处理 借助getType
let type = this.getType(url);
let fs = wx.getFileSystemManager()
// url为文件URL, name为文件名
//downloadFile 运用 filePath 指定文件下载后存储的路径 (本地路径) 即我们要用到 wx.env.USER_DATA_PATH 创建路径和临时文件tem.pdf然后进行改名
wx.downloadFile({
url: url,
filePath: wx.env.USER_DATA_PATH + `/${name}${type}`,
success: function (res) {
if (res.statusCode === 200) {
let filePath = res.tempFilePath;
//存诸文件名为我们清除缓存(本地用户文件最多10M,因此需要解决,避免占用存诸)
let delectFile = wx.getStorageSync('filePath', delectFile) ? wx.getStorageSync('filePath', delectFile):[];
delectFile = [...delectFile, wx.env.USER_DATA_PATH + `/${name}${type}`]
wx.setStorageSync('filePath', delectFile)
wx.openDocument({
filePath: wx.env.USER_DATA_PATH + `/${name}${type}`,
success: function (res) {
console.log('打开文档成功')
},
fail: function (res) {
wx.showToast({
title: 'fail',
icon: 'none'
})
}
})
}
},
fail: function (res) {
console.log('fail')
console.log(res)
},
})
清除缓存的代码
一开始我清除缓存是用在生命周期的onHide和onUnload上苹果手机没问题,但安卓手机打开有问题不能正常访问。通过排除知道苹果是在微信内置浏览器进行浏览文件,而安卓是通过系统自带软件进行浏览文件。而安卓这样做会导致小程序生命周期触发进行删除。因此最终决定在打开PDF前调用清除缓存的方法
//重复删除之前缓存的文件
let delectFile = wx.getStorageSync('filePath', delectFile);
if (!delectFile.length) return
let that = this;
let fs = wx.getFileSystemManager()
console.log(delectFile.length)
if (!delectFile.length) return
for (let i = 0; i < delectFile.length; i++) {
fs.unlink({
filePath: delectFile[i],
success: res => {
},
fail: res => {
console.log('删除失败')
}
})
}
delectFile = [];
wx.setStorageSync('filePath', delectFile)