js+php实现同时并发上传多个文件或文件夹
当我们上传大型文件或者很多文件(比如一个文件夹,包含很多子文件和子目录),如果采用传统的方式,一个接一个上传,可定很慢,那么有没有一种方式可以同时将所有的文件并行上传到服务器,最后汇总一下,有点像hadoop的map/reduce的模式,答案肯定是有的,js本身就是机遇event的异步单线程设计,异步的特性决定了不必等地io时间,直接去处理其他的事情。好了,那么首先解决怎么同时上传多个文件和文件夹的事情。
一、怎么选择文件夹和多个文件?
上传多个文件(multiple 属性ie9以上才支持)
<input type="file" name="file" multiple="multiple" />上传整个文件夹目录(webkitdirectory属性只有chrome及chrome内核的浏览器和火狐支持)
<input type='file' name="file" webkitdirectory />//那么接下来解决怎么同时上传的问题
二、怎么同时上传?
思路一、我们将多个文件放进Formdata构建form数据结合ajax来启动上传,代码如下
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>BFW NEW PAGE</title> <script id="bfwone" data="dep=jquery.17&err=0" type="text/javascript" src="http://repo.bfw.wiki/bfwrepo/js/bfwone.js"></script> <script type="text/javascript"> var files = []; bready(function() { $("#uploadfolder").change(function() { files = this.files; }); $("#upload-btn").click(function() { var fd = new FormData(); console.log(files); for (var i = 0; i < files.length; i++) { fd.append("file[]", files[i]); } $.ajax({ type: 'POST', url: "/FolderUpload", data: fd, cache: false, processData: false, contentType: false, dataType: 'json', success: function (ret) {}, complete: function(XMLHttpRequest, textStatus) {} }); }); }); </script> <style> </style> </head> <body> <input type='file' id="uploadfolder" name="file" multiple="multiple" /> <button id="upload-btn">上传多个文件</button> </body> </html>
那么后端php怎么接受呢
<?php function reArrayFiles(&$file_post) { $file_ary = array(); $file_count = count($file_post['name']); $file_keys = array_keys($file_post); for ($i=0; $i<$file_count; $i++) { foreach ($file_keys as $key) { $file_ary[$i][$key] = $file_post[$key][$i]; } } return $file_ary; } if ($_FILES['file']) { $file_ary = reArrayFiles($_FILES['file']); foreach ($file_ary as $file) { move_uploaded_file($file["tmp_name"],"upload/" . $file["name"]);//移动上传文件到自定义目录存储 print 'File Name: ' . $file['name']; print 'File Type: ' . $file['type']; print 'File Size: ' . $file['size']; } } ?>
好了,多文件上传解决了,但是有个问题,如果文件比较多,比较大,就会出现卡住,超时等情形,那怎么办呢,
思路二、我们可以将每个文件上传单独一个ajax上传到后端,后端启用多线程或多进程来同时处理上传,这样就加快了上传的速度。
今天我们通过promise异步调用来执行并行上传。
Promise,他是一个对象,是用来处理异步操作的,可以让我们写异步调用的时候写起来更加优雅,更加美观便于阅读。
具体代码如下:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>BFW NEW PAGE</title> <script id="bfwone" data="dep=jquery.17&err=0" type="text/javascript" src="http://repo.bfw.wiki/bfwrepo/js/bfwone.js"></script> <script type="text/javascript"> var files = []; bready(function() { $("#uploadfolder").change(function() { files = this.files; }); $("#upload-btn").click(function() { var fileret = new Array(); //上传结果存储数组 const uploadfilepromise = function(file) { return new Promise((resovle, reject) => { var fd = new FormData(); fd.set('file', file); $.ajax({ type: 'POST', url: "/FolderUpload", data: fd, cache: false, processData: false, contentType: false, dataType: 'json', error: function (ret) { reject(ret); }, success: function (ret) { if (ret.err) { fileret.push(ret); //如果上传失败 } resovle(ret); }, complete: function(XMLHttpRequest, textStatus) {} }); }); }; var filellist = new Array(); //本地文件 for (i = 0; i < files.length; i++) { filellist.push(files[i]); } console.log(filellist); let promises = filellist.map((item, index) => { return uploadfilepromise(item); }); // 并行执行 Promise.all(promises) .then(() => { if (fileret.length > 0) { console.log('部分上传失败') } else { console.log('全部上传成功') } fileret = null; console.log('上传完成') }) .catch(() => { console.log('上传错误error') }) }); }); </script> <style> </style> </head> <body> <input type='file' id="uploadfolder" name="file" multiple="multiple" /> <button id="upload-btn">上传多个文件</button> </body> </html>那么后端php还是采用简单的单一文件上传方式,为啥,因为后端是多线程多进程的,同时处理,每个进程或线程处理一个文件。
<?php if ($_FILES["file"]["error"] > 0) { echo "Error: " . $_FILES["file"]["error"] . "<br />"; } else { move_uploaded_file( $_FILES["file"]["tmp_name"],"upload/" . $_FILES["file"]["name"]);//移动上传文件到自定义目录存储 echo "Upload: " . $_FILES["file"]["name"] . "<br />"; echo "Type: " . $_FILES["file"]["type"] . "<br />"; echo "Size: " . ($_FILES["file"]["size"] / 1024) . " Kb<br />"; echo "Stored in: " . $_FILES["file"]["tmp_name"]; } ?>文件夹的上传方式与这个雷同,请查看另一篇博文,http://blog.bfw.wiki/user10/15590389971771170059.html
网友评论1