网上很多文件切片上传的文章, 看了很多, 最终自己总结了下, 主要思路如下:
1. 需要实现的功能
- 前端多文件上传
- 前端文件切片, 并命名uuid
- 文件同步上传, 切片同步上传
- 后端接受切片并根据文件名称保存至文件夹
- 后端判断是否是最后一个切片,合并切片
2.用到的技术
- h5文件切片
切片上传请求参数:
filename: file-5bad6aab-cf7d-bfdb-356a-36d7b4ab1e1e.jpg
fragname: frag-1e0d1311-2369-317b-262e-04a9f427ea8c
file: (binary)
fragindex: 0
total: 2
- es6 async await
- php monolog composer包
3. 开始写代码
3.1 前端
html:
<input multiple type="file" id="file" name="file" value="选择文件">
<button id="upload" type="button">上传文件</button>
点击上传, 获取所有的文件,并处理文件
$("#upload").click(function () {
var file = document.getElementById("file");
//获取所有文件
var fileList = file.files;
//操作文件
handleFiles(fileList);
return false;
});
处理文件方法:
文件上传同步,上传文件
async function handleFiles(fileList) {
var i = 0;
while (i<fileList.length){
console.log("=================================================");
console.log('开始处理第' + i + "个文件, 文件是" + fileList[i]['name'] + "大小是:" + fileList[i]['size'] );
var targetFile = fileList[i];
totalSize += targetFile.size;
await uploadFile(targetFile,i);
i++;
if(i == fileList.length) return;
}
}
处理上传文件切片,并上传
//upload file
async function uploadFile(targetFile,index) {
//console.log(targetFile);
var tmp = targetFile.name.split(".");
var filename = "file-"+guid() + '.' + tmp[tmp.length-1] ;
var fileSize = targetFile.size;
var total = Math.ceil( fileSize / pieceSize );
await handle();
async function handle() {
var i = 0;
var start = end = 0;
while(i < total){
end = start + pieceSize;
if(end >= fileSize){
end = fileSize;
}
console.log( '文件的index:' + index+ '| 处理文件切片 i:'+i , 'start:' + start, 'end:' + end );
var frag = targetFile.slice(start, end);
await send( filename,frag,i , total ,function () {
console.log( '文件的index:' + index+ "| 切片上传完成 回调 res111",i)
});
start = end;
i++;
}
}
}
//send
async function send(filename,frag,index,total,cb) {
var formData = new FormData();
var fragname = "frag-" + guid();
formData.append("filename",filename);
formData.append("fragname",fragname);
formData.append("file",frag);
formData.append("fragindex",index);
formData.append("total",total);
await $.ajax({
url: url,
type: 'POST',
cache: false,
data: formData,
processData: false,
contentType: false
}).done(function (res) {
//console.log('res:' + index);
cb && cb();
}).fail(function (res) {
});
}
3.2 后台php
<?php
header("Access-Control-Allow-Origin: *");
header("Content-type: text/html; charset=utf-8");
include "helper.php";
define ('SITE_ROOT', realpath(dirname(__FILE__)));
define("FILEPATH",realpath(dirname(__FILE__)) . "/dir/files/" );
define("FRAGPATH",realpath(dirname(__FILE__)) . "/dir/frags/" );
require_once "../vendor/autoload.php";
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
// create a log channel
$log = new Logger('my_app');
$log->pushHandler(new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG));
$file = $_FILES['file'];
//打印文件
$log->info('切片',$file);
$orgFileName = $_POST['filename'];
$log->info("orgFileName:" . $orgFileName);
//获取文件名称
$filename = explode("." , $_POST['filename']);
//获取文件后缀
$ext = $filename[1];
$filename = $filename[0];
$log->info("ext:" . $ext);
//新建frag 文件夹, 以filename为命名方式
if(!file_exists(FRAGPATH.$filename)){
mkdir(FRAGPATH.$filename);
}
//将接收到的frag文件移入file文件夹中
//$frag_path = SITE_ROOT.'/dir/'.$filename.'/'.iconv('UTF-8','gbk',basename($_FILES['file']['tmp_name']));
$frag_path = FRAGPATH.$filename ."/". $_POST['fragname'];
try{
if(move_uploaded_file($_FILES['file']['tmp_name'] , $frag_path)){
echo response(["status" => "上传成功"]);
}
}catch (Exception $e){
throw new Exception();
}
//合并file文件夹中的frag为最终文件
if( $_POST['fragindex'] == $_POST["total"] -1 ){
$blob = "";
$fragDir = FRAGPATH.$filename;
$handler = @opendir($fragDir);
//获取filename
while ( ( $fragFileName = readdir($handler) ) !== false ){
$fp = fopen( FILEPATH . '/' . $orgFileName,"ab" );
// 务必使用!==,防止目录下出现类似文件名“0”等情况
if ($fragFileName !== "." && $fragFileName !== "..")
{
//方式一:
//$blob .= file_get_contents( $fragDir . "/" . $fragFileName );
//方式二:
$value = $fragDir . "/" . $fragFileName;
$handle = fopen($value,"rb");
fwrite($fp,fread($handle,filesize($value)));
fclose($handle);
//删除切片文件
@unlink($fragDir . "/" . $fragFileName);
}
}
//合并切片到文件
//file_put_contents( FILEPATH. "/" . $filename . ".". $ext , $blob );
//删除切片文件夹
@rmdir($fragDir);
}
最终文件上传成功删除切片文件夹下的切片
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。