当前位置: 首页 > news >正文

胖咯科技网站建设成都做小程序定制开发多少钱

胖咯科技网站建设,成都做小程序定制开发多少钱,投资公司网站建设需求,做网站asp用什么软件大文件分片上传 效果展示 前端 思路 前端的思路#xff1a;将大文件切分成多个小文件#xff0c;然后并发给后端。 页面构建 先在页面上写几个组件用来获取文件。 bodyinput typefile idfile /button iduploadButton…大文件分片上传 效果展示 前端 思路 前端的思路将大文件切分成多个小文件然后并发给后端。 页面构建 先在页面上写几个组件用来获取文件。 bodyinput typefile idfile /button iduploadButton点击上传/button /body功能函数生成切片 切分文件的核心函数是 slice没错就是这么的神奇啊 我们把切好的 chunk 放到数组里等待下一步的包装处理 /*** 默认切片大小 10 MB*/ const SIZE 10 * 1024 * 1024;/*** 功能生成切片*/ function handleCreateChunk(file, size SIZE) {const fileChunkList [];let cur 0;while (cur file.size) {fileChunkList.push({file: file.slice(cur, cur size),});cur size;}return fileChunkList; }功能函数请求逻辑 在这里简单封装一下 XMLHttpRequest /*** 功能封装请求* param {*} param0* returns*/ function request({ url, method post, data, header {}, requestList }) {return new Promise((resolve, reject) {let xhr new XMLHttpRequest();xhr.open(method, url);Object.keys(header).forEach((item) {xhr.setRequestHeader(item, header[item]);});xhr.onload function (e) {resolve({data: e.target.response,});};xhr.send(data);}); }功能函数上传切片 /*** 功能 上传切片* 包装好 FormData 之后通过 Promise.all() 并发所有切片*/ async function uploadChunks(hanldleData, fileName) {const requestList hanldleData.map(({ chunk, hash }) {const formData new FormData();formData.append(chunk, chunk);formData.append(hash, hash);formData.append(filename, fileName);return formData;}).map((formData) {request({// url: http://localhost:3001/upload,url: upload,data: formData,});});await Promise.all(requestList); }/*** 功能触发上传 */ document.getElementById(uploadButton).onclick async function () {// 切片const file document.getElementById(file).files[0];console.log(file);const fileName file.name;const fileChunkList handleCreateChunk(file);// 包装const hanldleData fileChunkList.map(({ file }, index) {return {chunk: file,hash: ${fileName}_${index},};});await uploadChunks(hanldleData, fileName); };可以在请求中看到有很多个请求并发的上传 后端 后端的思路是 把 Node 暂存的 chunk 文件转移到我想处理的地方也可以直接处理看你的创建写入流把各个 chunk 合并前端会给你每个 chunk 的大小还有 hash 值来定位每个 chunk 的位置 获取 chunk 切片文件 先把上传的接口写好 const Koa require(koa); const Views require(koa-views); const Router require(koa-router); const Static require(koa-static); const { koaBody } require(koa-body); const fs require(fs); const fse require(fs-extra);const app new Koa(); const router new Router(); app.use(Views(__dirname)); app.use(Static(__dirname)); app.use(koaBody({multipart: true,formidable: {maxFields: 1000 * 1024 * 1024,},}) );router.get(/, async (ctx) {await ctx.render(index.html); });/*** 功能上传接口* - 从 ctx.request.body 中获取 hash 以及 filename* - 从 ctx.request.files 中拿到分片数据* - 然后再把 node 帮我们临时存放的 chunk 文件的 filepath 拿到之后移动到我们想要存放的路径下* - filepath 和 hash 是一一对应的关系*/ router.post(/upload, async (ctx) {const { hash, filename } ctx.request.body;const { filepath } ctx.request.files?.chunk;const chunkPath ${__dirname}/chunkPath/${filename};if (!fse.existsSync(chunkPath)) {await fse.mkdirs(chunkPath);}await fse.move(filepath, ${chunkPath}/${hash});ctx.body {code: 1,}; });app.use(router.routes()); app.listen(3000, () {console.log(server start: http://localhost:3000); });写完这些就可以拿到 chunk 合并接口 先写一个接口用来拿到 hash、文件名 /*** 功能: merge 接口* - hasMergeChunk 变量是上面用来记录的* - mergePath 定义一下合并后的文件的路径*/ router.post(/merge, async (ctx) {// console.log(ctx.request.body);const { fileName, size } ctx.request.body;hasMergeChunk {};const mergePath ${__dirname}/merge/${fileName};if (!fse.existsSync(${__dirname}/merge)) {fse.mkdirSync(${__dirname}/merge);}await mergeChunk(mergePath, fileName, size);ctx.body {data: 成功,}; });合并分片的功能函数 然后开始合并 /*** 功能合并 Chunk* - 1. chunkDir: 是 chunks 文件们所在的文件夹的路径* - 2. chunkPaths: 是个 Array数组中包含所有的 chunk 的 path* - 3. 因为 每个 chunk 的 path 命名是通过 hash 组成的所以我们先排序一下* - 算是为 createWriteStream 中的 start 做准备* - 4. 为每个 chunk 的 path 创建写入流写到 mergePath 这个路径下。因为已经* - 排序了所以 start 就是每个文件的 index * eachChunkSize* param {*} mergePath* param {*} name* param {*} eachChunkSize*/ async function mergeChunk(mergePath, name, eachChunkSize) {const chunkDir ${__dirname}/chunkPath/${name};const chunkPaths await fse.readdir(chunkDir);chunkPaths.sort((a, b) a.split(_)[1] - b.split(_)[1]);await Promise.all(chunkPaths.map((chunk, index) {const eachChunkPath ${chunkDir}/${chunk};const writeStream fse.createWriteStream(mergePath, {start: index * eachChunkSize,});return pipeStream(eachChunkPath, writeStream);}));console.log(合并完成);fse.rmdirSync(chunkDir);console.log(删除 ${chunkDir} 文件夹); }接着就是写入流 /*** 功能创建 pipe 写文件流* - 1. [首先了解一下什么是输入输出流](https://www.jmjc.tech/less/111)* - 2. hasMergeChunk 变量用于记录一下那些已经合并完成了也可以写成数组都行。* - 3. 可以检测输出流的 end 事件表示我这个 chunk 已经流完了然后写一下善后逻辑。* param {*} path* param {*} writeStream* returns*/ let hasMergeChunk {}; function pipeStream(path, writeStream) {return new Promise((resolve) {const readStream fse.createReadStream(path); // 输出流readStream.pipe(writeStream); // 输出通过管道流向输入readStream.on(end, () {hasMergeChunk[path] finish;fse.unlinkSync(path); // 删除此文件resolve();console.log(合并 No.${path.split(_)[1]}, 已经合并${Object.keys(hasMergeChunk).length});});}); }至此一个基本的逻辑上传就做好了 Q A 发送片段之后的合并可能出现错误 这个情况分析了一下是前端的锅啊前端的 await Promise.all() 并不能保证后端的文件流都写完了。 完整代码 前端 !DOCTYPE html html langenheadmeta charsetUTF-8 /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/titlescript srcrequest.js/script/headbodyinput typefile idfile /button iduploadButton点击上传/buttonbutton idmergeButton点击合并/button/bodyscript/*** 默认切片大小 10 MB*/const SIZE 10 * 1024 * 1024;/*** 功能生成切片*/function handleCreateChunk(file, size SIZE) {const fileChunkList [];let cur 0;while (cur file.size) {fileChunkList.push({file: file.slice(cur, cur size),});cur size;}return fileChunkList;}/*** 功能 上传切片* - 注意 map 里别忘了写 return*/async function uploadChunks(hanldleData, fileName) {const requestList hanldleData.map(({ chunk, hash }) {const formData new FormData();formData.append(chunk, chunk);formData.append(hash, hash);formData.append(filename, fileName);return formData;}).map((formData) {return request({url: upload,data: formData,});});await Promise.all(requestList).then((res) {console.log(所有上传结束, res);});console.log(发送合并请求);await request({url: merge,headers: {content-type: application/json,},data: JSON.stringify({size: SIZE,fileName,}),});}document.getElementById(uploadButton).onclick async function () {// 切片const file document.getElementById(file).files[0];const fileName file.name;const fileChunkList handleCreateChunk(file);// 包装const hanldleData fileChunkList.map(({ file }, index) {return {chunk: file,hash: ${fileName}_${index},};});await uploadChunks(hanldleData, fileName);};// document.getElementById(mergeButton).onclick async function () {// await request({// url: merge,// headers: {// content-type: application/json,// },// data: JSON.stringify({// size: SIZE,// fileName: 116 Mb.mkv,// }),// });// };/script /html后端 const Koa require(koa); const Views require(koa-views); const Router require(koa-router); const Static require(koa-static); const { koaBody } require(koa-body); const fse require(fs-extra);const app new Koa(); const router new Router(); app.use(Views(__dirname)); app.use(Static(__dirname)); app.use(koaBody({multipart: true,formidable: {maxFields: 1000 * 1024 * 1024,},}) );router.get(/, async (ctx) {await ctx.render(index.html); });/*** 功能上传接口* - 从 ctx.request.body 中获取 hash 以及 filename* - 从 ctx.request.files 中拿到分片数据* - 然后再把 node 帮我们临时存放的 chunk 文件的 filepath 拿到之后移动到我们想要存放的路径下* - filepath 和 hash 是一一对应的关系*/ router.post(/upload, async (ctx) {const { hash, filename } ctx.request.body;const { filepath } ctx.request.files?.chunk;const chunkPath ${__dirname}/chunkPath/${filename};if (!fse.existsSync(chunkPath)) {await fse.mkdirs(chunkPath);}await fse.move(filepath, ${chunkPath}/${hash});ctx.body {code: 1,}; });/*** 功能创建 pipe 写文件流* - 1. [首先了解一下什么是输入输出流](https://www.jmjc.tech/less/111)* - 2. hasMergeChunk 变量用于记录一下那些已经合并完成了也可以写成数组都行。* - 3. 可以检测输出流的 end 事件表示我这个 chunk 已经流完了然后写一下善后逻辑。* param {*} path* param {*} writeStream* returns*/ let hasMergeChunk {}; function pipeStream(path, writeStream) {return new Promise((resolve) {const readStream fse.createReadStream(path); // 输出流readStream.pipe(writeStream); // 输出通过管道流向输入readStream.on(end, () {hasMergeChunk[path] finish;fse.unlinkSync(path); // 删除此文件resolve();console.log(合并 No.${path.split(_)[1]}, 已经合并${Object.keys(hasMergeChunk).length});});}); }/*** 功能合并 Chunk* - 1. chunkDir: 是 chunks 文件们所在的文件夹的路径* - 2. chunkPaths: 是个 Array数组中包含所有的 chunk 的 path* - 3. 因为 每个 chunk 的 path 命名是通过 hash 组成的所以我们先排序一下* - 算是为 createWriteStream 中的 start 做准备* - 4. 为每个 chunk 的 path 创建写入流写到 mergePath 这个路径下。因为已经* - 排序了所以 start 就是每个文件的 index * eachChunkSize* - 5. 每个写入流都用 Promise 包装了一下然后用 await Promise.all() 等待处理完* param {*} mergePath* param {*} name* param {*} eachChunkSize*/ async function mergeChunk(mergePath, name, eachChunkSize) {const chunkDir ${__dirname}/chunkPath/${name};const chunkPaths await fse.readdir(chunkDir);chunkPaths.sort((a, b) a.split(_)[1] - b.split(_)[1]);await Promise.all(chunkPaths.map((chunk, index) {const eachChunkPath ${chunkDir}/${chunk};// 创建输入流并为每个 chunk 定好位置const writeStream fse.createWriteStream(mergePath, {start: index * eachChunkSize,});return pipeStream(eachChunkPath, writeStream);}));console.log(合并完成);fse.rmdirSync(chunkDir);console.log(删除 ${chunkDir} 文件夹); }/*** 功能: merge 接口* - hasMergeChunk 变量是上面用来记录的* - mergePath 定义一下合并后的文件的路径*/ router.post(/merge, async (ctx) {// console.log(ctx.request.body);const { fileName, size } ctx.request.body;hasMergeChunk {};const mergePath ${__dirname}/merge/${fileName};if (!fse.existsSync(${__dirname}/merge)) {fse.mkdirSync(${__dirname}/merge);}await mergeChunk(mergePath, fileName, size);ctx.body {data: 成功,}; });app.use(router.routes()); app.listen(3000, () {console.log(server start: http://localhost:3000); }); request.js 的封装 /*** 功能封装请求* param {*} param0* returns*/ function request({ url, method post, data, headers {}, requestList }) {return new Promise((resolve, reject) {let xhr new XMLHttpRequest();xhr.open(method, url);Object.keys(headers).forEach((item) {xhr.setRequestHeader(item, headers[item]);});xhr.onloadend function (e) {resolve({data: e.target.response,});};xhr.send(data);}); }
http://www.pierceye.com/news/422065/

相关文章:

  • 做阿里巴巴网站多少钱如何卸载安装wordpress
  • 企业综合型网站建设方案成都比较好的装修设计公司
  • 网吧手机网站模版网络网站推广首荐乐云seo
  • 网站添加支付功能网上能免费做网站发布叼
  • 哪里有做美食的视频网站关键词搜索量查询工具
  • 科技公司企业网站源码门户建设目标
  • wordpress 公司网站 模板 下载网站主办者是谁
  • 教学网站开发源码北京做网站建设价格低
  • 淄博网站seo公司北京酒店团购网站建设
  • 长治网站制作哪家好手机排行榜网站
  • 公司自建网站需要多少钱即时设计生成网页
  • 东台网站建设服务商广州市网站建设公
  • eclipse可以做门户网站嘛北京十大平面设计公司
  • 德文网站建设有趣的网站 知乎
  • 西安做推广网站设计wordpress 移动适配
  • 网站建设续费合同sousou提交网站入口
  • 怎么快速推广网站商城网站离不开支付系统
  • 我想在阿里巴巴上给别人做网站模板网站建设价位
  • 百度如何验证网站网站开发入什么科目
  • 不要验证码的广告网站迁安建设局官方网站
  • 开发网站私活wordpress 被墙
  • 安徽索凯特建设工程有限公司网站wordpress虚拟资源
  • 做购物网站安全吗河南网站平台建设公司
  • 网站台做计么呢wordpress微信插件开发
  • 外贸电商网站制作网站开发数据库问题
  • 如何推广个人网站广州关键词优化外包
  • 长沙专业网站建设公司排名运城网站建设专业服务商
  • 建设银行宁波招聘网站会议管理系统
  • 重庆 网站开发如何将网站提交到搜索引擎
  • 怎么把网站封包做app网页设计基础开题报告及网页流程图