news 2026/7/14 6:58:35

微信小程序下载超过200MB的文件

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
微信小程序下载超过200MB的文件

查看微信的官方文档

DownloadTask wx.downloadFile(Object object)

以 Promise 风格 调用:不支持

小程序插件:支持,需要小程序基础库版本不低于 1.9.6

微信 Windows 版:支持

微信 Mac 版:支持

微信 鸿蒙 OS 版:支持

相关文档: 网络使用说明、局域网通信

功能描述

下载文件资源到本地。客户端直接发起一个 HTTPS GET 请求,返回文件的本地临时路径 (本地路径),单次下载允许的最大文件为 200MB。使用前请注意阅读相关说明。

注意:请在服务端响应的 header 中指定合理的Content-Type字段,以保证客户端正确处理文件类型。

参数

Object object

属性类型默认值必填说明最低版本
urlstring下载资源的 url
headerObjectHTTP 请求的 Header,Header 中不能设置 Referer
timeoutnumber60000超时时间,单位为毫秒,默认值为 60000 即一分钟。2.10.0
filePathstring指定文件下载后存储的路径 (本地路径)1.8.0

文档标识只支持200MB的文件,那么我们如何下载超过200MB的文件呢

我尝试通过分块下载来实现这个逻辑,先把文件拆分成多个子文件下载下来,然后再一起合并成最终的视频。

import {authorize} from "./download"; const fs = wx.getFileSystemManager(); const fileName = 'video.mp4' // 下载的文件名 const tempFilePath = wx.env.USER_DATA_PATH + '/downloads4_' // 临时文件存储路径 // const FILE_PATH = `${wx.env.USER_DATA_PATH}/downloaded_video.mp4`; // 最终合并输出路径 const BLOCK_SIZE = 1024 * 1024 * 300; // 每块大小:5MB /** * 获取远程视频文件大小 */ function getFileSize(url) { return new Promise((resolve, reject) => { uni.request({ url, method: 'HEAD', success: (res) => { const size = parseInt(res.header['Content-Length'] || res.header['content-length']); resolve(size); }, fail: reject, }); }); } /** * 下载单个分块并写入临时 chunk 文件 */ function downloadChunk(url, start, end, index,callback) { return new Promise((resolve, reject) => { // uni.request({ // url, // header: { // Range: `bytes=${start}-${end}`, // }, // responseType: 'arraybuffer', // success: (res) => { // const chunkPath = `${wx.env.USER_DATA_PATH}/chunk_${index}`; // fs.writeFile({ // filePath: chunkPath, // data: res.data, // encoding: 'binary', // success: resolve, // fail: reject, // }); // }, // fail: reject, // }); authorize().then(() => { console.log(`${tempFilePath}${index}`) const tmpFile = wx.env.USER_DATA_PATH + '/downloads4_'+index+".mp4" const task = wx.downloadFile({ url: `${url}?t=${new Date().getTime()}`, //仅为示例,并非真实的资源 // header: { // Range: `bytes=${start}-${end}`, // }, // filePath:tmpFile, // filepath: tmpFile, success: (res) => { console.log(res); if (res.statusCode >= 200 && res.statusCode < 300) { wx.saveVideoToPhotosAlbum({ filePath: res.tempFilePath, success:function(res) { console.log(res) resolve(); // wx.hideLoading(); }, fail: (err) => { console.log(err) reject(new Error('Download chunk fail.')) } }) } else { reject(new Error('Download chunk error.')) } }, fail: (err) => { console.log(err) reject(new Error('Download chunk fail.')) } }) task?.onProgressUpdate((res) => { const { progress, totalBytesWritten, totalBytesExpectedToWrite } = res console.log('下载进度' + progress); console.log('已经下载的数据长度' + totalBytesWritten); console.log('预期需要下载的数据总长度' + totalBytesExpectedToWrite); if (callback) { callback(res); }else{ uni.showToast({ icon: "none", title: `下载进度: ${progress}%`, }); } if (totalBytesExpectedToWrite > MaxTotalSize) { const CurTotalSizeMB = (totalBytesExpectedToWrite / 1024 / 1024).toFixed(2); // FailReason.errMsg = `当前文件${CurTotalSizeMB}MB,小程序单次下载允许的最大文件仅为${MaxTotalSizeMB}MB。您可复制下载链接,切换到本地浏览器自行下载!`; task.abort(); return; } }) }) }); } /** * 合并所有 chunk 成一个完整文件 */ function mergeChunks(chunkCount, targetFilePath) { return new Promise((resolve, reject) => { try { // 清空或创建目标文件 fs.writeFileSync(targetFilePath,'', 'binary' ); for (let i = 0; i < chunkCount; i++) { // const chunkPath = `${wx.env.USER_DATA_PATH}/chunk_${i}`; const chunkPath = wx.env.USER_DATA_PATH + '/downloads4_'+i+".mp4"; console.log("chunkPath:"+chunkPath); const chunkData = fs.readFileSync(chunkPath, 'binary'); fs.appendFileSync( targetFilePath, chunkData, 'binary', ); // 删除临时 chunk fs.unlinkSync(chunkPath); } resolve(); } catch (err) { console.log(err) reject(err); } }); } // 合并已下载的分片文件 function mergeFiles(chunkCount) { const fs = wx.getFileSystemManager() const stream = fs.createWriteStream(`${wx.env.USER_DATA_PATH}/downloads4_${fileName}`) const write = (index) => { console.log("开始合并"+index); const path = wx.env.USER_DATA_PATH + '/downloads4_'+index+".mp4"; // const path = `${wx.env.USER_DATA_PATH}/chunk_${index}`; // const chunk = chunks[index] // if (!chunk.downloaded) { // console.log(`Chunk ${chunk.index} not downloaded.`) // return // } fs.readFile(path, 'binary', (err, data) => { if (err) { console.log(err) return } stream.write(data, 'binary') if (index < chunkCount - 1) { write(index + 1) } else { // 文件合并完成 stream.end() // this.resetState() } }) } write(0) } /** * 下载完整视频,带进度回调 */ async function downloadVideoWithChunks(url, callback) { const totalSize = await getFileSize(url); console.log("totalSize:"+totalSize); const chunkCount = Math.ceil(totalSize / BLOCK_SIZE); for (let i = 0; i < chunkCount; i++) { const start = i * BLOCK_SIZE; const end = Math.min(start + BLOCK_SIZE - 1, totalSize - 1); await downloadChunk(url, start, end, i,callback); // if (onProgress) { // onProgress(i + 1, chunkCount); // } } const fullPath = `${wx.env.USER_DATA_PATH}/downloads4_${fileName}` console.log('fullPath', fullPath) // await mergeChunks(chunkCount,fullPath); // await mergeFiles(chunkCount); return fullPath; } /** * 保存文件到相册,带权限检查 */ function requestPermissionAndSave(filePath) { return new Promise((resolve, reject) => { uni.getSetting({ success(settingRes) { if (!settingRes.authSetting['scope.writePhotosAlbum']) { uni.authorize({ scope: 'scope.writePhotosAlbum', success: () => { uni.saveVideoToPhotosAlbum({ filePath, success: resolve, fail: reject, }); }, fail: () => { uni.showModal({ title: '提示', content: '请授权保存到相册', success(res) { if (res.confirm) wx.openSetting(); }, }); reject(new Error('未授权')); }, }); } else { uni.saveVideoToPhotosAlbum({ filePath, success: resolve, fail: reject, }); } }, fail: reject, }); }); } /** * 主函数:分块下载 + 合并 + 保存 */ export async function downloadAndSaveVideo(url, onProgress) { try { const path = await downloadVideoWithChunks(url, onProgress); // await requestPermissionAndSave(path); uni.showToast({ title: '保存成功', icon: 'success' }); } catch (err) { console.error('下载或保存失败:', err); uni.showToast({ title: '失败', icon: 'none' }); } }

但在分块的逻辑下,虽然下载子文件是没有问题,但是在最终合成大视频的环节中还是会报200mb限制大小的错误,所以这个方案还是不可行的。

最后的最后,我神奇的发现,其实wx.downloadFile 是支持超过200MB的文件,你不要自己定义filePath,你用它自己返回的文件路径就好

const Task = uni.downloadFile({

// url: url, //仅为示例,并非真实的资源

url: `${url}?t=${new Date().getTime()}`, //仅为示例,并非真实的资源

// filepath: filePath, // 之前我这里自定义了路径,这里需要注释掉

timeout: 300 * 1000, // 设置特定超时时间5分钟

success: (res) => {

你用它返回的res.tempFilePath 去保存 (要用真机调试,开发者工具做了200MB的拦截)

wx.saveVideoToPhotosAlbum({

filePath: res.tempFilePath,

success:function(res) {

resolve();

// wx.hideLoading();

},

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/13 10:47:01

EmotiVoice能否替代专业配音员?业内专家这样说

EmotiVoice能否替代专业配音员&#xff1f;业内专家这样说 在短视频日更、AI主播直播带货已成常态的今天&#xff0c;一个现实问题正摆在内容创作者面前&#xff1a;我们是否还需要花数万元请专业配音员录制一段旁白&#xff1f;当一条情感充沛的语音可以由几行代码在几秒内生成…

作者头像 李华
网站建设 2026/7/13 15:17:49

《缺失的第一个正数:原地哈希算法的理论与实践》

摘要缺失的第一个正数问题是数组处理领域的经典算法问题&#xff0c;要求在未排序整数数组中找出未出现的最小正整数&#xff0c;同时需满足时间复杂度 O(n) 与常数级额外空间的约束。本文以 ** 原地哈希&#xff08;置换法&#xff09;** 为核心&#xff0c;系统分析其算法原理…

作者头像 李华
网站建设 2026/7/13 12:16:00

微爱帮监狱写信寄信平台阿里云真人实名认证API对接技术方案

一、系统概述1.1 项目背景微爱帮作为特殊群体通信服务平台&#xff0c;为确保信件邮寄的真实性和安全性&#xff0c;需要对用户进行严格的实名认证。通过对接阿里云实名认证服务&#xff0c;实现身份证人脸的双重验证&#xff0c;保障通信双方身份真实性。1.2 认证流程┌───…

作者头像 李华
网站建设 2026/7/14 8:15:54

23、Linux 文件管理与操作全解析

Linux 文件管理与操作全解析 1. 基础文件查看命令 - ls ls 命令是 Linux 中用于查看文件和目录的基础命令,它有多种参数可以组合使用,以满足不同的查看需求。以下是一些常见的 ls 命令示例: | 命令 | 解释 | | — | — | | ls /etc/samba | 列出 /etc/samba 目录…

作者头像 李华
网站建设 2026/7/13 0:58:18

好写作AI驾到!论文“肝”到emo?你的赛博学术搭子已上线

还在对着空白文档“挤牙膏”&#xff1f;文献读得头晕眼花&#xff0c;格式调得怀疑人生&#xff1f;别慌&#xff0c;你的智能学术伙伴已携“黑科技”前来救场&#xff01;好写作AI官方网址&#xff1a;https://www.haoxiezuo.cn/一、学术写作的“痛苦金字塔”&#xff1a;你在…

作者头像 李华
网站建设 2026/7/14 0:41:40

EmotiVoice语音合成系统灰度放量策略与风险控制

EmotiVoice语音合成系统的灰度放量实践与风险治理 在智能语音交互日益普及的今天&#xff0c;用户早已不再满足于“能说话”的机器。他们期待的是有温度、有情绪、像真人一样能共情的声音。然而&#xff0c;传统文本转语音&#xff08;TTS&#xff09;系统往往受限于固定音色、…

作者头像 李华