关于uniapp下载文件遇见的坑及总结

===============【需求:在小程序中将后端返回的字节流写入文件并转发】==============

==============【中间一堆是记录走的弯路,可跳过,最后两段代码是最终结果】==========

背景:服务器将生成的文件二进制流返回给前端,(即服务器写入本地文件,需要下载时读文件内容并通过response 的 outputStream返回给前端)
原需求:仅有网页版,采用构造<a href=''>的方式通过浏览器下载,体验很好,网上文章很多,不做赘述。

后续需求:要求做个app或小程序,方便客户使用,经过尝试,上述<a >的方式不再适用,效果如下(该方法并不规范,是通过将网页版程序build 后的 dist文件 放进5+App中运行出来的),解决未果

第二次尝试:创建uni-app项目,使用uni.downloadFile接口,该方法下载之后,日志提示下载成功,但通过返回路径再进行 uni.saveFile, 报路径不存在。将路径打印出来检查发现确实不存在,很迷。经过百度发现以下方法可以成功:

export function createFlie(fileName, data) {
  return new Promise(resolve => {//这里封装了个是一个promise异步请求
    // plus.io.requestFileSystem是请求本地文件系统对象
    plus.io.requestFileSystem(
    	plus.io.PUBLIC_DOCUMENTS, // 文件系统中的根目录下的DOCUMENTS目录
    	fs => {
    		// 创建或打开文件, fs.root是根目录操作对象,直接fs表示当前操作对象
    		fs.root.getFile(fileName, {
    			create: true // 文件不存在则创建
    		}, fileEntry => {
    			// 文件在手机中的路径
    			console.log(fileEntry.fullPath)
    			fileEntry.createWriter(writer => {
    				// 写入文件成功完成的回调函数
    				writer.onwrite = e => {
    					console.log("写入本地文件成功");
						resolve("写入本地文件")
    				};
    				// 写入数据
    				writer.write(JSON.stringify(data));
    			})
    		}, e => {
    			console.log("getFile failed: " + e.message);
    		});
    	},
    	e => {
    		console.log(e.message);
    	}
    );
  })
}

第三次尝试:由于做 ios app太麻烦,放弃,转战小程序。注意:坑又来了,上述方法仅适用于app,因为plus是安卓和ios的增强类,在小程序中会报 “plus 未定义”。换 wx.downloadFile 接口,微信文档:网络 / 下载 / wx.downloadFile (qq.com)
贴出数据处理部分:

uni.request({
	url: `${BASE_URI}/products/download-lk`,
	method: 'POST',
	data: frmIds,
	header: {
		'content-type': 'application/json',
		'Authorization': 'Bearer ' + wx.getStorageSync('token')
		},
	responseType: 'arraybuffer',
	success: (res2) => {
		if (res2.data instanceof ArrayBuffer) {
		    // createFlie(fileName, res.data)
		    var url_file = wx.createBufferURL(new Uint8Array(res2.data))
		    //writeFile(fileName, url_file)
		    dowloadFile(fileName, url_file)
	    }
	},
	fail(err) {
		console.log(err)
	}
})
export function dowloadFile(fileName, url_file) {
	var path = `${wx.env.USER_DATA_PATH}/` + fileName
	console.log('url: ', url_file)
	wx.downloadFile({
		url: url_file,
		filePath: path,
		success(res) {
		  console.log("成功:", res)
			uni.showModal({
				title: '下载成功',
				content:'是否分享该文件',
				showCancel: true,
				success: function(res) {
					if (res.confirm){
						wx.shareFileMessage({
							filePath: path,
							success() {
								console.log("分享成功")
							},
							fail(err) {
								console.log("分享失败: ", err)
							}
						})
					}
				}
			})
		},
		fail(err) {
			console.log(err)
		}
	})
}

在小程序调试中该方法可以正常下载,不出意外的话就不会出意外,发布体验版测试,该来的它还是来了,protocol must be http or https

打印出来看一下,小程序开发工具里,是http

真机调试中

这个问题我没有去深究,采用备选方案:自己写入文件,但如果直接将resData写入,下载的文件大小是不对的

终极解决方案它来了:先读再写
文档:文件 / FileSystemManager / FileSystemManager.readFile (qq.com)

export function writeFile(fileName, resData) {
	var path = `${wx.env.USER_DATA_PATH}/` + fileName
	console.log("wx path: ", path)
	const fs = wx.getFileSystemManager()
	fs.readFile({
		filePath: resData,
		success(res) {
			console.log("文件读取成功")
			fs.writeFile({
			  filePath: path,
			  data: res.data,
			  success(res) {
			    console.log("成功:", res)
				uni.showModal({
					title: '下载成功',
					content:'是否分享该文件',
					showCancel: true,
					success: function(res) {
						if (res.confirm){
							wx.shareFileMessage({
								filePath: path,
								success() {
									console.log("分享成功")
								},
								fail(err) {
									console.log("分享失败: ", err)
								}
							})
						}
					}
				})
			  },
			  fail(res) {
			    console.error("失败: ", res)
			  }
			})
		},
		fail(err) {
			console.log(err)
		}
	})
}

最后终于成功拿到了文件并解析成功,中间还经历了文件内容处理的坎坷,我这个文件是二进制格式的,处理方法都在上面的代码里了

后续:读写的方法,在安卓上可以下载成功,ios上不行

==============================【最终结果】=================================


后经过调整发现走了弯路,最终解决方案,获取到buffer,直接写,真机调试安卓,ios均可用

uni.request({
				url: `${BASE_URI}/products/download-lk`,
				method: 'POST',
				data: frmIds,
				header: {
					'content-type': 'application/json',
					'Authorization': 'Bearer ' + wx.getStorageSync('token')
				},
				responseType: 'arraybuffer',
				success: (res2) => {
					if (res2.data instanceof ArrayBuffer) {
						var url_file = wx.createBufferURL(new Uint8Array(res2.data))
						writeFile(fileName, new Uint8Array(res2.data).buffer)
					}
				},
				fail(err) {
					console.log(err)
				}
			})
export function writeFile(fileName: string, data: ArrayBuffer) {
	var path = `${wx.env.USER_DATA_PATH}/` + fileName
	console.log("wx path: ", path)
	const fs = wx.getFileSystemManager()
	fs.writeFile({
		filePath: path,
		data: data,
		success(res) {
			shareFile(path) //调用 wx.shareFileMessage
		},
		fail(res) {
			wx.showToast({
				title: '下载失败',
				icon: 'error'
			})
			console.error("写入文件失败: ", res)
		}
	})
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值