废话不多说,直接看代码

html代码

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>分块上传文件测试</title>
  6. </head>
  7. <body>
  8. <input type="file" id="my_file" name="my_file"/>
  9. </body>
  10. <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
  11. <script>
  12. $('#my_file').on("change", function () {
  13. let file = this.files[0];//文件
  14. let block_size = 1024 * 1024;//每一个块的大小
  15. let total_num = Math.ceil(file.size / block_size);//向上取整,得到分块的个数
  16. let start = 0;//默认分块的开始位置
  17. let end = block_size;//默认分块的结束位置
  18. let parr = [];//这里为Promise.all准备一个数组
  19. let file_id = Date.now().toString() + RandomNumBoth(100, 999).toString()//为此文件设置一个唯一ID号
  20. for (let i = 1; i <= total_num; i++) {
  21. start = (i - 1) * block_size;//分块开始位置
  22. end = start + block_size;//分块结束位置
  23. if (end > file.size) {
  24. end = file.size;//这里对最后一个分块的结束位置进行调整
  25. }
  26. let blob = file.slice(start, end);//进行分块
  27. //创建formData对象
  28. let form_data = new FormData();
  29. form_data.append("file", blob)//分块的文件
  30. form_data.append("sort", i.toString());//序号
  31. form_data.append("file_id", file_id);//文件ID
  32. form_data.append("flag", "0");//这里flag=0表示上传的是文件
  33. // formData组装好之后,调用upload()函数,返回一个promise对象,并把它放入parr数组中,方便后面的promise.all方法使用
  34. parr.push(upload(form_data));
  35. }
  36. Promise.all(parr).then(res => {
  37. if (res.length === parr.length) {
  38. $.ajax({
  39. type: "post",
  40. url: "/upload.php",
  41. data: {
  42. "file_id": file_id,//此文件的唯一ID号
  43. "flag": "1",// 这里flag=1表示上传完成,请求组装
  44. "suffix": file.name.substring(file.name.lastIndexOf(".") + 1),//文件后缀用于合并后文件的后缀
  45. },
  46. success: function (res) {
  47. console.log(res)
  48. },
  49. error: function () {
  50. console.log(222)
  51. },
  52. });
  53. }
  54. })
  55. });
  56. // 这个函数用来上传分片文件,返回的是一个promise对象,方便后面使用promise.all还判断所有分片是否是上传成功的
  57. // 这里要说明一下,$.post()是不可以上传文件的,只能用$.ajax()并且要把contentType:false和processData:false带上
  58. function upload(form_data) {
  59. return new Promise((resolve, reject) => {
  60. $.ajax({
  61. type: "post",
  62. url: "/upload.php",
  63. data: form_data,
  64. contentType: false,
  65. processData: false,
  66. success: function (res) {
  67. resolve(res)
  68. },
  69. error: function () {
  70. reject()
  71. }
  72. });
  73. })
  74. }
  75. /**
  76. * 生成指定范围的随机数
  77. * @param min
  78. * @param max
  79. * @returns {number}
  80. * @constructor
  81. */
  82. function RandomNumBoth(min, max) {
  83. return Math.round(Math.random() * (max - min) + min);
  84. }
  85. </script>
  86. </html>

php代码

  1. <?php
  2. $tem_dir = "./tem_dir"; //定义临时文件文件夹
  3. $upload_dir = "./upload"; //定义上传文件夹
  4. $file = $_FILES["file"]; //获取上传的文件
  5. $flag = $_POST["flag"]; //获取标志,1表示上传完成需要合并文件,0表示上传文件
  6. $sort = $_POST["sort"]; //序号
  7. $ID = $_POST["ID"]; //文件唯一标志
  8. $tem_file_dir = $tem_dir . "/" . $ID; //每一批临时文件存放的文件夹
  9. if (!$flag) {
  10. //上传文件
  11. if (!is_dir($tem_file_dir)) {
  12. mkdir($tem_file_dir, 0777, true);
  13. }
  14. move_uploaded_file($file["tmp_name"], $tem_file_dir . "/" . $sort);
  15. exit(json_encode(["err" => 0]));
  16. }
  17. //合并文件
  18. $suffix = $_POST["suffix"]; //文件后缀
  19. $file_arr = scandir($tem_file_dir); //扫描这一批临时文件
  20. //去除数组中的 . 和 ..
  21. $new_file_arr = [];
  22. foreach ($file_arr as $k => $v) {
  23. if ($v != "." && $v != "..") {
  24. $new_file_arr[] = $v;
  25. }
  26. }
  27. if (!is_dir($upload_dir)) {
  28. mkdir($upload_dir, 0777, true);
  29. }
  30. //按照序号排序
  31. sort($new_file_arr);
  32. //写入文件
  33. $new_file = fopen($upload_dir . "/" . $ID . "." . $suffix, "a");
  34. foreach ($new_file_arr as $k => $v) {
  35. fwrite($new_file, file_get_contents($tem_file_dir . "/" . $v));
  36. unlink($tem_file_dir . "/" . $v);
  37. }
  38. fclose($new_file);
  39. rmdir($tem_file_dir);
  40. exit(json_encode(["err" => 0]));