前端如何实现大文件上传
  9m65el8SCpbP 2023年11月19日 21 0

在开发过程中,经常会遇到一些较大文件上传,如果只使用一次请求去上传文件,一旦这次请求中出现什么问题,那么无论这次上传了多少文件,都会失去效果,用户则需要重新上传所有资源。所以就想到一种方式,将一个大文件分成多个小文件,这样通过多个请求实现大文件上传。

接下来我们就来看看具体是怎么实现的~


<input type="file" id="update-btn">

  <script>

    const updateInput = document.querySelector('#update-btn')

    updateInput.onchange = () => {

      const file = updateInput.files[0]

      if(!file){

        return

      }

    // 通过file的slice 方法可以将文件进行分割,第一个参数是从哪个字节开始,第二个参数是到哪个字节结束

      const chunk = file.slice(0,2000) 

  }

  </script>


这时候我们在控制台可以得到 chunk 是

前端如何实现大文件上传_spark

 这时,我们知道了如何将大文件进行切片,那么我们就创建个函数用于对文件进行切片


const updateInput = document.querySelector('#update-btn')

    updateInput.onchange = () => {

      const file = updateInput.files[0]

      if(!file){

        return

      }

      const chunkList = chunkFileFun(file, 1*1024*1024)

    }

    /**

    * @description: 文件分片函数

    * @param {

    *   file: 需要分片的文件,

    *   size: 文件按照每片多大去分片

    * }

    * @return: [] 文件分片后的数组

    */

    const chunkFileFun = ( file, size ) => {

      const result = []

      for (let i = 0; i < file.size; i += size) {

        result.push(file.slice( i, i + size))

      }

      return result

    }

 这时候我们可以看控制台,我们已经获取到了分片的数组

前端如何实现大文件上传_spark_02

 

这样就结束了吗?并没有~ 如果我们再上传到一半的时候失败了,我们并希望下次上传文件重新上传,我们希望通过和服务器交互知道我们上次上传文件上传到哪里,我们从没有上传的切片继续上传就好了,那么这个东西我们应该如何实现呢?

我在这里使用的是spark-md5这个插件生成一个固定的hash值。大家也可以使用其他方式生成固定的hash值,我们上传的时候通过这个hash值,和服务端交互确认我们上传的是哪个文件上传到哪里,这样就可以解决我们的问题了


<script type="text/javascript" src="./spark-md5.min.js"></script>

  <input type="file" id="update-btn">

  <script>

    const updateInput = document.querySelector('#update-btn')

    updateInput.onchange = async () => {

      const file = updateInput.files[0]

      if (!file) {

        return

      }

      console.log('file', file)

      const chunkList = chunkFileFun(file, 1 * 1024 * 1024)

      console.log('chunkList', chunkList)

      const hash = await getHash(chunkList)

    }

    /**

    * @description: 获取文件hash

    * @param {file: 文件}

    * @return: hash

    */

    const getHash = (chunkList) => {

      const spark = new SparkMD5()

      return new Promise(resolve => {

        const chunkHash = (i) => {

          if (i >= chunkList.length) {

            resolve(spark.end())

            return

          }

          const blob = chunkList[i]

          const read = new FileReader()

          read.onload = e => {

            // 读取到的字节数量

            const byte = e.target.result

            spark.append(byte)

            chunkHash(i + 1)

          }

          read.readAsArrayBuffer(blob)

        }

        chunkHash(0)

      })

    }

    /**

    * @description: 文件分片函数

    * @param {

    *   file: 需要分片的文件,

    *   size: 文件按照每片多大去分片

    * }

    * @return: [] 文件分片后的数组

    */

    const chunkFileFun = (file, size) => {

      const result = []

      for (let i = 0; i < file.size; i += size) {

        result.push(file.slice(i, i + size))

      }

      return result

    }

  </script>

 在这个计算hash过程中需要读取整个文件的内容,这个过程时间会很长,我们一般不会在主线程做这个事,以免页面卡死,我们可以通过web worker,开辟另外一个线程去做这个事情。


参考文章:http://blog.ncmem.com/wordpress/2023/10/10/前端如何实现大文件上传/




【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月19日 0

暂无评论

推荐阅读
9m65el8SCpbP