废话不多说,直接看代码
html代码
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>分块上传文件测试</title></head><body><input type="file" id="my_file" name="my_file"/></body><script src="http://code.jquery.com/jquery-2.1.1.min.js"></script><script> $('#my_file').on("change", function () { let file = this.files[0];//文件 let block_size = 1024 * 1024;//每一个块的大小 let total_num = Math.ceil(file.size / block_size);//向上取整,得到分块的个数 let start = 0;//默认分块的开始位置 let end = block_size;//默认分块的结束位置 let parr = [];//这里为Promise.all准备一个数组 let file_id = Date.now().toString() + RandomNumBoth(100, 999).toString()//为此文件设置一个唯一ID号 for (let i = 1; i <= total_num; i++) { start = (i - 1) * block_size;//分块开始位置 end = start + block_size;//分块结束位置 if (end > file.size) { end = file.size;//这里对最后一个分块的结束位置进行调整 } let blob = file.slice(start, end);//进行分块 //创建formData对象 let form_data = new FormData(); form_data.append("file", blob)//分块的文件 form_data.append("sort", i.toString());//序号 form_data.append("file_id", file_id);//文件ID form_data.append("flag", "0");//这里flag=0表示上传的是文件 // formData组装好之后,调用upload()函数,返回一个promise对象,并把它放入parr数组中,方便后面的promise.all方法使用 parr.push(upload(form_data)); } Promise.all(parr).then(res => { if (res.length === parr.length) { $.ajax({ type: "post", url: "/upload.php", data: { "file_id": file_id,//此文件的唯一ID号 "flag": "1",// 这里flag=1表示上传完成,请求组装 "suffix": file.name.substring(file.name.lastIndexOf(".") + 1),//文件后缀用于合并后文件的后缀 }, success: function (res) { console.log(res) }, error: function () { console.log(222) }, }); } }) }); // 这个函数用来上传分片文件,返回的是一个promise对象,方便后面使用promise.all还判断所有分片是否是上传成功的 // 这里要说明一下,$.post()是不可以上传文件的,只能用$.ajax()并且要把contentType:false和processData:false带上 function upload(form_data) { return new Promise((resolve, reject) => { $.ajax({ type: "post", url: "/upload.php", data: form_data, contentType: false, processData: false, success: function (res) { resolve(res) }, error: function () { reject() } }); }) } /** * 生成指定范围的随机数 * @param min * @param max * @returns {number} * @constructor */ function RandomNumBoth(min, max) { return Math.round(Math.random() * (max - min) + min); }</script></html>
php代码
<?php$tem_dir = "./tem_dir"; //定义临时文件文件夹$upload_dir = "./upload"; //定义上传文件夹$file = $_FILES["file"]; //获取上传的文件$flag = $_POST["flag"]; //获取标志,1表示上传完成需要合并文件,0表示上传文件$sort = $_POST["sort"]; //序号$ID = $_POST["ID"]; //文件唯一标志$tem_file_dir = $tem_dir . "/" . $ID; //每一批临时文件存放的文件夹if (!$flag) { //上传文件 if (!is_dir($tem_file_dir)) { mkdir($tem_file_dir, 0777, true); } move_uploaded_file($file["tmp_name"], $tem_file_dir . "/" . $sort); exit(json_encode(["err" => 0]));}//合并文件$suffix = $_POST["suffix"]; //文件后缀$file_arr = scandir($tem_file_dir); //扫描这一批临时文件//去除数组中的 . 和 ..$new_file_arr = [];foreach ($file_arr as $k => $v) { if ($v != "." && $v != "..") { $new_file_arr[] = $v; }}if (!is_dir($upload_dir)) { mkdir($upload_dir, 0777, true);}//按照序号排序sort($new_file_arr);//写入文件$new_file = fopen($upload_dir . "/" . $ID . "." . $suffix, "a");foreach ($new_file_arr as $k => $v) { fwrite($new_file, file_get_contents($tem_file_dir . "/" . $v)); unlink($tem_file_dir . "/" . $v);}fclose($new_file);rmdir($tem_file_dir);exit(json_encode(["err" => 0]));