大文件分片下载(文件流形式)

大文件分片下载

上一篇文章写到大文件上传,当大文件从后端传到前端时,如果是普通的文件流接口下载时,浏览器默认解析,文件大的情况,浏览器的内存会爆掉,这就是使用大文件分片下载的意义,需要和后端配合解析.

整体思路

1.需要先将整个文件的打包文件大小向后端获取.
2.再将文件的字节大小分割,再次向接口获取对应的字节(切记顺序不能错乱)
3.前端将文件拼接并下载.

页面代码

<template>
  <div>
    <!--面包屑导航-->
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
      <el-breadcrumb-item>大文件上传和下载</el-breadcrumb-item>
      <el-breadcrumb-item>大文件下载</el-breadcrumb-item>
    </el-breadcrumb>
    <!--卡片视图-->
    <el-card>
      <el-table
        :data="list"
        border
        style="width: 100%">
        <el-table-column
          fixed
          prop="fileName"
          label="文件名称">
        </el-table-column>
        <el-table-column
          fixed="right"
          label="操作">
          <template slot-scope="scope">
            <el-progress v-if="showPercent" :text-inside="true" :stroke-width="15" :percentage="percent"></el-progress>
            <el-button v-else @click="handleDownload(scope.row)" type="text" size="small">下载</el-button>
          </template>
        </el-table-column>
      </el-table>

    </el-card>
  </div>
</template>

获取文件大小

handleDownload(row) {
      // 获取文件大小进行分片 FILE_ZIP_DATA =  [{
      //   fileName: '大文件',
      //     fileSize: 100 * 1024 * 1024
      // }]
      this.showPercent = true;
      this.$axios.post('getZipFile', {...row}).then(res => {
        //  静态的 接口文件FILE_ZIP_DATA
        res = FILE_ZIP_DATA
        this.file.size = res.size;
        this.file.fileName = res.fileName;
        const total = Math.ceil(res.size / this.size);
        this.downloadFile(total)
      }).catch(() => {
        this.showPercent = false;
        this.percent = 0;
      })
    },

切割文件并下载合并

    // 下载文件
    downloadFile(total) {
      let len = total;
      const list = [];
      let fileArr = [];
      let percentNum = 1;
      for (let i = 0, len = total; i < len; i++) {
        list.push({
          fileName: this.file.fileName,
          // 切片范围,判断最后一次切片和最后一次切片的文件大小
          bytes: `bytes = ${i * this.size}-${i + 1 >= total ? this.fize.size : (i + 1) * this.size}`
        })
      }
      // 将文件的分隔后分片接口下载并push到新的数组中,并且按照顺序(分片的顺序,切记不能错乱)
      list.forEach((val, idx) => {
        this.$axios.post('exportFile', val, {
          headers: {
            // 设置取部分的字节
            Range: val.bytes
          },
          // 将接口设置成blob格式
          responseType: 'blob'
        }).then(res => {
          len--;
          if (res) {
            // 进度条
            this.percent = Math.floor(percentNum / total * 100);
            fileArr[idx] = res;
            percentNum++;
            if (len === 0) {
              this.saveFileDownload(arr);
            }
          }
        })
      })
    },
    // 合并文件保存
    saveFileDownload(fileArr) {
      const saveFile = new Blob(fileArr);
      saveAs(saveFile, '大文件的名字');
      setTimeout(() => {
        this.showPercent = false;
        this.percent = 0;
      })
    },

完整代码

<template>
  <div>
    <!--面包屑导航-->
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
      <el-breadcrumb-item>大文件上传和下载</el-breadcrumb-item>
      <el-breadcrumb-item>大文件下载</el-breadcrumb-item>
    </el-breadcrumb>
    <!--卡片视图-->
    <el-card>
      <el-table
        :data="list"
        border
        style="width: 100%">
        <el-table-column
          fixed
          prop="fileName"
          label="文件名称">
        </el-table-column>
        <el-table-column
          fixed="right"
          label="操作">
          <template slot-scope="scope">
            <el-progress v-if="showPercent" :text-inside="true" :stroke-width="15" :percentage="percent"></el-progress>
            <el-button v-else @click="handleDownload(scope.row)" type="text" size="small">下载</el-button>
          </template>
        </el-table-column>
      </el-table>

    </el-card>
  </div>
</template>

<script>
import {FILE_ZIP_DATA} from "@/mock/data";

export default {
  name: 'Params',
  data() {
    return {
      list: [],
      columns: [],
      showPercent: false,
      // 进度条
      percent: 0,
      size: 50 * 1024 * 1024,
      file: {
        fileName: "",
        size: 0,
        dataStream: []
      }
    }
  },
  // categories
  mounted() {
    this.init();
  },
  methods: {
    // 初始化
    init() {
      this.getData();
    },
    handleDownload(row) {
      // 获取文件大小进行分片 FILE_ZIP_DATA =  [{
      //   fileName: '大文件',
      //     fileSize: 100 * 1024 * 1024
      // }]
      this.showPercent = true;
      this.$axios.post('getZipFile', {...row}).then(res => {
        //  静态的 接口文件FILE_ZIP_DATA
        res = FILE_ZIP_DATA
        this.file.size = res.size;
        this.file.fileName = res.fileName;
        const total = Math.ceil(res.size / this.size);
        this.downloadFile(total)
      }).catch(() => {
        this.showPercent = false;
        this.percent = 0;
      })
    },
    // 下载文件
    downloadFile(total) {
      let len = total;
      const list = [];
      let fileArr = [];
      let percentNum = 1;
      for (let i = 0, len = total; i < len; i++) {
        list.push({
          fileName: this.file.fileName,
          // 切片范围,判断最后一次切片和最后一次切片的文件大小
          bytes: `bytes = ${i * this.size}-${i + 1 >= total ? this.fize.size : (i + 1) * this.size}`
        })
      }
      // 将文件的分隔后分片接口下载并push到新的数组中,并且按照顺序(分片的顺序,切记不能错乱)
      list.forEach((val, idx) => {
        this.$axios.post('exportFile', val, {
          headers: {
            // 设置取部分的字节
            Range: val.bytes
          },
          // 将接口设置成blob格式
          responseType: 'blob'
        }).then(res => {
          len--;
          if (res) {
            // 进度条
            this.percent = Math.floor(percentNum / total * 100);
            fileArr[idx] = res;
            percentNum++;
            if (len === 0) {
              this.saveFileDownload(arr);
            }
          }
        })
      })
    },
    // 合并文件保存
    saveFileDownload(fileArr) {
      const saveFile = new Blob(fileArr);
      saveAs(saveFile, '大文件的名字');
      setTimeout(() => {
        this.showPercent = false;
        this.percent = 0;
      })
    },
    getData() {
      // 调用接口
      this.list = [{
        id: 1,
        fileName: '大文件'
      }]
    }
  }
}
</script>

<style lang="less" scoped>
.cat_opt {
  margin: 15px 0;
  width: 200px;
}
</style>

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值