• 大文件切片功能


    近期接到的新需求:上传大文件,因文件上传的大小不定,所以需要切片上传
    前端代码:

    import md5 from "js-md5";
    
    /**
     * 缓存转换  导入大文件
     * @param {*} that   this
     * @param {*} file 上传文件的对象
     * @param {*} size   每次上传文件的限制大小
     * @param {*} progress 上传文件的进度条
     * @param {*} url string 上传文件的url
    
     * @param {*} module_name  string   上传文件的需要上文的文件名
     */
    export function uploadFile(that, file, size, progress, url, module_name) {
      let xhr = new XMLHttpRequest();
      let form_data = new FormData();
      let start = 0;
      let end = start + that.size;
      let blob;
      let blob_num = 1;
    
      blob = cutFile(file);
      sendFile(blob, file);
      blob_num += 1;
    
      //切割文件
      function cutFile(file) {
        let file_blob = file.slice(start, end);
        start = end;
        end = start + that.size;
        return file_blob;
      };
    
      //发送文件
      function sendFile(blob, file) {
        let total_blob_num = Math.ceil(file.size / size);
        form_data = new FormData();
        form_data.append('file', blob);
        form_data.append('blob_num', blob_num);
        form_data.append('total_blob_num', total_blob_num);
        form_data.append('file_name', file.name);
        form_data.append('module_name', module_name);
        form_data.append('code', md5(md5(file.name + global.ENCRYPTION_KEY)));
        xhr.open("POST", global.IMG_URL + url, false);
        xhr.onreadystatechange = function () {
          if (total_blob_num == 1) {
            that.progress = 100;
          } else {
            that.progress = Math.min(100, (blob_num / total_blob_num) * 100);
          }
          if (JSON.parse(xhr.response).code == 0) {
            that.file_name = '';
            that.$Message.error('上传错误');
            return false
          } else if (JSON.parse(xhr.response).code == 2) {
            that.$Message.success('上传成功');
            that.file_path = JSON.parse(xhr.response).file_path;
            return false
          }
          let t = setTimeout(function () {
            if (start < file.size) {
              blob = cutFile(file);
              sendFile(blob, file);
              blob_num += 1;
            } else {
              clearTimeout(t);
            }
          }, 1000);
        }
        xhr.send(form_data);
      }
    }

    后端代码:我们后端是用PHP完成的

    <?php
    
    if (!defined('BASEPATH')) exit('No direct script access allowed');
    header('Content-Type:text/html;charset=utf-8');
    
    header('Access-Control-Allow-Origin:*');
    
    class chunkupload extends CI_Controller
    {
        private $filepath; // 上传目录
        private $tmpPath; // PHP文件上传临时目录
        private $blobNum; // 当前第几个文件块
        private $totalBlobNum; // 文件块总数
        private $fileName; // 原文件名
        private $finalFileName; // 经过处理的最终文件名
    
        public function __construct()
        {
            parent::__construct();
        }
    
        // 大文件分片上传
        public function bigFileUpload()
        {
            if (empty($_POST['code'])) {
                echo_json(0,'code不能为空');
            }
    
            if (empty($_POST['module_name'])) {
                echo_json(0,'上传目录不能为空');
            }
    
            if (empty($_POST['blob_num'])) {
                echo_json(0,'当前片数不能为空');
            }
    
            if (empty($_POST['file_name'])) {
                echo_json(0,'文件名不能为空');
            }
    
            if (empty($_POST['total_blob_num'])) {
                echo_json(0,'总片数不能为空');
            }
    
            if (empty($_FILES['file'])) {
                echo_json('file为空');
            }
    
            if (empty($_FILES['file']['tmp_name'])) {
                echo_json(0,'tmp_name为空');
            }
    
            $fileDir = './uploads/'.trim($_POST['module_name'],'/').'/' . date('Y/m/d');
            $this->filepath = $fileDir;
            $this->tmpPath = $_FILES['file']['tmp_name'];
            $this->blobNum = $_POST['blob_num'];
            $this->totalBlobNum = $_POST['total_blob_num'];
            $this->fileName = $_POST['file_name'];
    
            // 校验
            $this->validate($_POST['code'], $_POST['file_name']);
            // 移动文件
            $this->moveFile();
            // 合并分块的文件
            $this->fileMerge();
            // 响应状态
            $this->apiReturn();
        }
    
        // 判断是否是最后一块,如果是则进行文件合成并且删除文件块
        private function fileMerge()
        {
            if($this->blobNum == $this->totalBlobNum){
                $blob = '';
                for($i=1; $i<= $this->totalBlobNum; $i++){
                    $blob .= file_get_contents($this->filepath.'/'. $this->fileName.'__'.$i);
                }
    
                $ext = '.'.substr(strrchr($this->fileName, '.'), 1);
                $this->finalFileName = date('YmdHis') . rand('10000', '99999') . $ext;
    
                file_put_contents($this->filepath.'/'. $this->finalFileName,$blob);
                $this->deleteFileBlob();
            }
        }
    
        // 删除文件块
        private function deleteFileBlob()
        {
            for($i=1; $i<= $this->totalBlobNum; $i++){
                @unlink($this->filepath.'/'. $this->fileName.'__'.$i);
            }
        }
    
        // 移动文件
        private function moveFile()
        {
            $this->touchDir();
            $filename = $this->filepath.'/'. $this->fileName.'__'.$this->blobNum;
            move_uploaded_file($this->tmpPath,$filename);
        }
    
        // API返回数据
        public function apiReturn()
        {
            header('Content-type: application/json');
            if($this->blobNum == $this->totalBlobNum){
                if(file_exists($this->filepath.'/'. $this->finalFileName)){
                    $data['code'] = 2;
                    $data['msg'] = 'success';
                    $data['file_path'] = ltrim($this->filepath,'./').'/'. $this->finalFileName;
                    echo json_encode($data);
                    exit;
                }
            }else{
                if(file_exists($this->filepath.'/'. $this->fileName.'__'.$this->blobNum)){
                    $data['code'] = 1;
                    $data['msg'] = '上传中,共:'.$this->totalBlobNum.'块,当前第'.$this->blobNum.'块....';
                    $data['file_path'] = '';
                    echo json_encode($data);
                    exit;
                }
            }
    
        }
    
        // 建立上传文件夹
        private function touchDir()
        {
            if(!file_exists($this->filepath)){
                return mkdir($this->filepath, 0777, true);
            }
        }
    
        // 参数校验
        private function validate($code,$fileName)
        {
            if (md5(md5($fileName.config_item('encryption_key'))) != $code) {
                echo_json(0,'参数校验失败');
            }
        }
    }
    
    function echo_json($code = 0, $msg = '', $data = array())
    {
        $arr = array(
            'code' => $code,
            'msg' => $msg,
            'data' => $data
        );
    
        echo json_encode($arr);
        exit;
    }
  • 相关阅读:
    Git 基础笔记整理1
    学习开源中国客户端
    IOS项目中的细节处理,如更改状态栏等等
    网络编程
    当FileWriter没有flush的时候,不写入文件
    批量移动文件
    批量重命名文件
    替换一个文件内的某个字符
    遍历map和删除map中的一个entry
    ArrayList的遍历-转载
  • 原文地址:https://www.cnblogs.com/mxyr/p/10343039.html
Copyright © 2020-2023  润新知