首页 > 其他分享 >js 大文件分片上传

js 大文件分片上传

时间:2024-04-11 11:59:41浏览次数:25  
标签:const data js file 分片 console chunkList 上传 hash

html需要使用 服务器的方式打开, 推荐使用 vscode Live Server 插件, 否则 无法加载本地的 worker.js

axios 和 spark-md5 自己去npmjs.com上找

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta
    name="viewport"
    content="width=device-width, initial-scale=1.0"
  >
  <title>Document</title>
</head>

<body>
  <input
    type="file"
    name=""
    id="file1"
  >

  <input
    type="file"
    name=""
    id="file2"
  >
  <script src="./axios.min.js"></script>
  <script>
    const PIECE_SIZE = 1024 * 1024 * 20
    const ipt = document.querySelector("#file1")
    ipt.addEventListener('change', ev => {
      const file = ev.target.files[0]
      // 分片
      const chunkList = []
      for (let i = 0; i < file.size; i += PIECE_SIZE) {
        chunkList.push(file.slice(i, i + PIECE_SIZE))
      }
      // 电脑一共有多少个线程
      const threadNum = navigator.hardwareConcurrency || 4
      // 每个线程要完成多少个切片任务
      const chunkNum = Math.ceil(chunkList.length / threadNum)

      let result = []
      for (let i = 0; i < threadNum; i++) {
        const worker = new Worker('./worker.js', { type: 'module' })
        const start = chunkNum * i
        const end = chunkNum * (i + 1) > chunkList.length ? chunkList.length : chunkNum * (i + 1)
        worker.postMessage({
          chunkList,
          start,
          end
        })

        console.time('cut')
        worker.onmessage = ({ data }) => {
          result = result.concat(data)
          if (result.length === chunkList.length) {
            console.timeEnd('cut')
            console.time('upload')
            uploadFile(result.sort((a, b) => a.index - b.index), file.name)
          }
        }
      }
    })

    function uploadFile(lis, name) {
      const hashs = lis.map(i => i.hash)

      axios({
        url: 'http://127.0.0.1:5000/build_file',
        method: 'post',
        headers: {
          'Content-Type': 'Application/json'
        },
        data: {
          hashs: hashs,
          name
        }
      }).finally(res => {
        console.timeEnd('upload')
        console.log(res, '重组文件成功')
      }).catch(err => {
        console.timeEnd('upload')
        console.log(err, '重组文件失败')
      })
    }
  </script>

  <script>
    const ipt2 = document.querySelector('#file2')
    ipt2.addEventListener('change', ev => {
      console.time('t1')
      const file = ev.target.files[0]
      const fd = new FormData()
      fd.append('file', file)
      axios({
        url: 'http://127.0.0.1:5000/load',
        method: 'post',
        headers: {
          'Content-Type': 'Application/form-data'
        },
        data: fd
      }).then(res => {
        console.timeEnd('t1')
        console.log(res, '文件上传成功')
      }).catch(err => {
        console.timeEnd('t1')
        console.log(err, '文件上传失败')
      })
    })
  </script>
</body>

</html>

worker.js

import './spark-md5.min.js';
import './axios.min.js'

function createChunk(list, index) {
  const blob = list[index]
  const spark = new SparkMD5.ArrayBuffer()
  return new Promise((resolve) => {
    const fr = new FileReader()
    fr.onload = async ev => {
      spark.append(ev.target.result)
      const hash = spark.end()
      const fd = new FormData()
      fd.append('hash', hash)
      fd.append('file', blob)
      axios({
        url: 'http://127.0.0.1:5000/upload',
        method: 'post',
        headers: {
          'Content-Type': 'Application/form-data'
        },
        data: fd
      }).then(res => {
        resolve({
          hash,
          index
        })
      }).catch(err => {
        resolve({
          hash,
          index
        })
      })

    }
    fr.readAsArrayBuffer(blob)
  })
}



onmessage = async function ({ data }) {
  const { start, end, chunkList } = data
  const taskList = []
  for (let i = start; i < end; i++) {
    taskList.push(createChunk(chunkList, i))
  }
  Promise.all(taskList).then(res => {
    postMessage(res)
  })
}

 

 

后端 python 代码

demo.py  需要在同级别建立一个 temp 文件

from flask import Flask, request
from flask_cors import CORS
import os

app = Flask(__name__)
CORS(app)


@app.route('/upload', methods=['POST'])
def upload():
    filename = request.form.get('hash')
    temp_file = request.files.get('file')
    temp_file.save('./temp/%s' % filename)

    return {
        'save': "success"
    }


@app.route('/build_file', methods=['POST'])
def build_file():
    filename = request.json.get('name')
    hashs = request.json.get('hashs')

    with open('./%s' % filename, 'ab') as file:
        for file_hash in hashs:
            with open('./temp/%s' % file_hash, 'rb') as temp:
                file.write(temp.read())
            os.remove('./temp/%s' % file_hash)
        return 'success'


@app.route('/load', methods=['POST'])
def load():
    file = request.files.get('file')
    file.save('./asd.exe')
    return 'success'


if __name__ == '__main__':
    app.run(debug=True)

 

标签:const,data,js,file,分片,console,chunkList,上传,hash
From: https://www.cnblogs.com/fmg0224/p/18128714

相关文章

  • nextJs中使用styled-jsx
    NextJs不支持直接在页面和组件里importCss这种引入方式(除了全局引入),但是可以使用styled-jsx的方式进行Css的样式定义,也可以实现样式加载NextJs中Css的几种使用方案: global全局引入:在main文件或者app.js/ts文件里面进行全局引入,这种只是适合全局作用的样式引入。例如:im......
  • vue2和vue3的js格式
    vue2<script>//exportdefault的作用是开放里定义的数据和方法exportdefault{name:'App',//和标签中绑定数据放在data(){}里data(){return{name:'张三',age:18,tel:'13888888888'}},......
  • 上传第三方jar包至maven私服,以geotools为例
    上传jar包(模块打包方式为jar)mvndeploy:deploy-file-DgroupId=org.geotools-DartifactId=gt-api-Dversion=10.3-Dpackaging=jar-Dfile=C:\Users\Nihaorz\Desktop\geotools\gt-api\10.3\gt-api-10.3.jar-Durl=http://192.168.100.154:8081/repository/geostack-releases......
  • 关于JSP的MVC设计(新手小白白week7速看)
    通过之前的学习JSP,我们发现我们可以用过Servlet来实现下图功能但是我们发现这样写也太麻烦了吧,而且工程量巨大,所以MVC设计应运而生在开始前,我们需要创建三个软件包,并且创建好我们需要的controller,dao,model相应文件通过需要在WEB-INF中创建目录views,同时把footer,header,i......
  • 比nestjs更优雅的ioc:跨模块访问资源
    使用ts的最佳境界:化类型于无形在项目中使用ts可以带来类型智能提示与校验的诸多好处。同时,为了减少类型标注,达到化类型于无形的效果,CabloyJS引入了ioc和依赖查找的机制。在上一篇文章中,我们创建了一个业务模块test-home,并且采用依赖查找的机制演示了如何优雅的定义和使用资源,包括......
  • 用代码验证,esm 导出的是值的引用,commonjs导出的是值的拷贝
    首先需要学习一下esm和commonjs的区别,其中一条关于导出值我们可以手动验证一下,先记住结论esm导出的是值的引用commonjs导出的是值的拷贝没错我又遇到这个问题了,面试官先问我commonjs和esm有啥区别?然后问如果commonjs导出一个模块,在模块内部改变一个值,模块外部......
  • jackson 使用jsonNode与objectNode 实现访问json对象, 操作json对象
    前情提要因为现有项目都用的阿里巴巴的fastjson做json串的序列化与反序列化,但是fastJson的漏洞太多了,经常处理扫描出来的漏洞时,需要升级版本,导致出现各种大大小小的bug,经过考究,决定使用jackSon做新项目的序列化与反序列化工作,那先看一下常用的场景:将对象转为js......
  • 认识学习JSON
    JSON:   json是一种轻量级的数据交换格式。   简单来说:json就是一种在各个编程语言中流通的数据格式,负责不同编程语言中的数据传递和交互。   json在js中提供了两种方法:  JSON.parse():将JSON数据转换为对象或数组。  JSON.stringify():将对象或......
  • JS中的JSON(秒懂如何操作JSON)
    目录一、JSON介绍1.概念2.主要特点3.优点 4.使用JSON的原因使用XML使用JSON 二、JSON语法三、JSON使用1.JSON的序列化2.解析(parse)JSON3.序列化(Stringify)JSON四、JSON实例1.用户信息2.本地存储五、JSON应用场景六、总结一、JSON介绍1.概念JSON(JavaS......
  • 002nestjs控制器(controller)
    一、控制器的作用控制器负责处理传入请求并向客户端返回响应二、使用方法新建/cats目录创建cats.controller.ts在里面添加如下内容import{Controller,Get}from'@nestjs/common';@Controller('cats')exportclassCatsController{@Get()findAll():string{......