news 2026/8/7 3:38:03

微信小程序下载超过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/8/7 3:38:02

[网络多媒体] 屏幕共享、远程桌面与视频流的本质差异与实战应用

在企业内网、家庭局域网以及跨网络远程协作中,屏幕共享(Screen Sharing)、远程桌面(Remote Desktop) 与 视频流(Video Streaming) 是三种常见的远程视听方案。它们常被误解为功能相近的技术,实际在底层实现、交互模型、性能需求和应用场景上存在显著差异。本文将从技术…

作者头像 李华
网站建设 2026/8/6 20:58:54

自建Elasticsearch 迁移至阿里云Elasticsearch

&#x1f4cc; 一、阿里云官方文档核心要求&#xff08;已全部落实&#xff09;要求本方案落实✅ ECS 与阿里云 ES 同 VPC已满足✅ 先全量 再增量&#xff0c;避免窗口丢失初次增量从 T0 开始✅ 增量字段必须为 date 类型lastActiveDate 已验证✅ ES 8.x 必须移除 document_ty…

作者头像 李华
网站建设 2026/8/6 12:19:00

芯谷科技—D2010:高效电机控制与保护的卓越之选

在现代工业自动化和智能设备领域&#xff0c;电机控制技术的精准与高效至关重要。D2010&#xff0c;作为一款由绍兴芯谷科技有限公司&#xff08;Silicore Technology&#xff09;推出的高性能相位控制电路&#xff0c;凭借其卓越的特性与功能&#xff0c;为电机控制领域带来了…

作者头像 李华
网站建设 2026/8/6 6:18:10

28、Linux系统备份与Samba 3.0新特性解析

Linux系统备份与Samba 3.0新特性解析 1. Linux客户端备份操作 在Linux客户端进行备份时,当登录到域中的Linux客户端计算机,用户名和密码通常是客户端本地的。若要连接到域PDC或成员服务器,需分别输入域用户名和密码。 在Linux GUI中,可通过Nautilus查看域中的计算机,具…

作者头像 李华
网站建设 2026/8/6 9:14:53

好写作AI全程伴写:论文从0到1的“通关攻略”大揭秘

写论文就像闯关打怪&#xff1f;从空白文档到完美成稿&#xff0c;你的“智能导航”已就位。今天我们不聊大道理&#xff0c;只拆解实实在在的“通关步骤”。好写作AI官方网址&#xff1a;https://www.haoxiezuo.cn/阶段一&#xff1a;选题构思期&#xff5c;告别“开局迷茫症”…

作者头像 李华
网站建设 2026/8/5 7:20:16

零基础也能玩转EmotiVoice?新手入门常见问题解答

零基础也能玩转EmotiVoice&#xff1f;新手入门常见问题解答 在虚拟主播深夜直播时突然“破防”痛哭&#xff0c;或游戏NPC因玩家挑衅而暴怒咆哮的瞬间——你是否想过&#xff0c;这些富有情绪张力的声音背后&#xff0c;可能只用了几秒钟的音频样本和一段开源代码&#xff1f…

作者头像 李华