前端代码

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="zh-CN">
<head>
<title>分割大文件上传</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
#test{
width: 200px;
height: 100px;
border: 1px solid green;
display: none;
}
#img{
width: 50px;
height: 50px;
display: none;
}
#upimg{
text-align: center;
font: 8px/10px '微软雅黑','黑体',sans-serif;
width: 300px;
height: 10px;
border: 1px solid green;
}
#load{
width: 0%;
height: 100%;
background: green;
text-align: center;
}
</style>
</head>
<body>
<form enctype="multipart/form-data" action="file.php" method="post">
<!--
<input type="file" name="pic" />
<div id="img"></div>
<input type="button" value="uploadimg" onclick="upimg();" /><br />
-->
<div id="upimg">
<div id="load"></div>
</div>
<input type="file" name="mof" multiple="multiple"/>
<input type="button" value="uploadfile" onclick="upfile();" />
<input type="submit" value="submit" />
</form>
<div id="test">
测试是否DIV消失
</div>
<script type="text/javascript"> var xhr=null; if (window.XMLHttpRequest)
{// code for all new browsers
xhr=new XMLHttpRequest();
}
else if (window.ActiveXObject)
{// code for IE5 and IE6
xhr=new ActiveXObject("Microsoft.XMLHTTP");
} if(xhr == null){
alert("Your browser does not support XMLHTTP."); } if (window.File && window.FileReader && window.FileList && window.Blob) {
// Great success! All the File APIs are supported.
} else {
alert('The File APIs are not fully supported in this browser.');
} var fd;
var des=document.getElementById('load');
var file;
const LENGTH=2*1024*1024;
var start;
var end;
var blob;
var pecent;
var filename;
//var pending;
//var clock;
function upfile(){
start=0;
end=LENGTH+start;
//pending=false; file=document.getElementsByName('mof')[0].files[0];
//filename = file.name;
if(!file){
alert('请选择文件');
return;
}
//clock=setInterval('up()',1000);
up(); } function up(){
/*
if(pending){
return;
}
*/
if(start<file.size){
xhr.open('POST','file.php',true);
//xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xhr.onreadystatechange=function(){
if(this.readyState==4){
if(this.status>=200&&this.status<300 || this.status == 304){
if(this.responseText.indexOf('failed') >= 0){
if(this.responseText.indexOf('success') >= 0){
alert('文件发送成功');
}else{
alert('文件发送失败,请重新发送');
des.style.width='0%';
} }else{
start=end;
end=start+LENGTH;
setTimeout('up()',100);
} }
}
}
xhr.upload.onprogress=function(ev){
if(ev.lengthComputable){
pecent=100*(ev.loaded+start)/file.size;
if(pecent>100){
pecent=100;
}
//num.innerHTML=parseInt(pecent)+'%';
des.style.width=pecent+'%';
des.innerHTML = parseInt(pecent)+'%'
}
}
       
  //分割文件核心部分slice
if(file.slice){
blob=file.slice(start,end);
}else if (file.webkitSlice) {
blob = file.webkitSlice(start, stop + 1);
} else if (file.mozSlice) {
blob = file.mozSlice(start, stop + 1);
}else{
alert('不支持slice上传');
return;
} fd=new FormData();
fd.append('mof',blob);
fd.append('test',file.name);
//console.log(fd);
//pending=true;
xhr.send(fd);
}else{
alert('上传成功');
}
} xhr.onerror = function(e){
console.log(e);
alert('服务器错误');
}
function change(){
des.style.width='0%';
} </script>
</body>
</html>

  PHP代码

<?php
/****
waited
****/
//print_r($_FILES);exit; $file = $_FILES['mof']; $type = trim(strrchr($_POST['test'], '.'),'.'); // print_r($_POST['test']);exit; if($file['error']==0){
if(!file_exists('./upload/upload.'.$type)){
if(!move_uploaded_file($file['tmp_name'],'./upload/.'.$type)){
echo 'failed';
}
}else{
$content=file_get_contents($file['tmp_name']);
if (!file_put_contents('./upload/.'.$type, $content,FILE_APPEND)) {
echo 'failed';
}
}
}else{
echo 'failed success';
} ?>

  

使用md5加密参数

使用es6的封装,支持断点续传

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>文件上传</title>
<script src="https://code.jquery.com/jquery-3.4.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/spark-md5/3.0.0/spark-md5.js"></script>
</head>
<body>
<h1>大文件上传测试</h1>
<div>
<h3>自定义上传文件</h3>
<input id="file" type="file" name="avatar"/>
<div>
<input id="submitBtn" type="button" value="提交">
</div>
</div>
<script type="text/javascript">
//开始插件代码
const blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
class FlieSlice {
constructor(opt){
let def = {
progress: function(){},
success: function(){},
fail: function(){},
chunkSize:2*1024*1024, // 每个chunk的大小,设置为2兆
userId:"" ,//如果传了用户的 id,通过 hash 记录在 localstorage ,就可以断点续传,不传 userid,则不考虑断点续传
autoUpload:true //自动上传
}; def = Object.assign(def,opt);
def.blockCount = Math.ceil(opt.file.size / def.chunkSize); // 分片总数
this.def = def; this.paused = false;
this.current = 0;
this.iscontinue = false; if(def.autoUpload){
this.send();
}
}
async send(){
try{
this.hash = await this.getHash(); //这个是文件的hash,可以再加上用户id,这样就可以做断点续传
if(this.def.userId){
//需要断点续传的判断
const prevIndex = window.localStorage.getItem(this.hash);
const index = Number(prevIndex);
if(prevIndex && index < this.def.blockCount){
//如果存在,说明之前这个文件没有传完
this.iscontinue = true;
this.upload(index);
}else{
//如果不存在,则不会继续了
this.upload();
}
}else{
this.upload();
} }catch(e){
console.warn(e);
this.paused = true;
}
}
upload(i){
i = i || 0;
const me = this;
const def = me.def;
const {file,blockCount,chunkSize} = def;
const hash = me.hash;
me.current = i; if(i >= blockCount || me.paused){
return ;
}
const start = i * chunkSize;
const end = Math.min(file.size, start + chunkSize);
if(start >= end){
return ;
}
console.log(`start:${start}_end:${end},${i}`);
def.progress && def.progress({
name:file.name,
file:blobSlice.call(file, start, end), // 当前的块
done: i >= blockCount-1, // 是否已经发送完
hash:hash, // hash
size:file.size, // 文件的总大小
index:i, // 当前传到了第几块
count:blockCount, // 总块数
iscontinue:me.iscontinue, //这次上,属于断点续传
next(err){ // 下次迭代.
if(err){
me.paused = true;
window.localStorage.removeItem(hash);
return ;
}
++i;
if(i < blockCount){
//每次上传,都记录 hash
window.localStorage.setItem(hash,i);
me.upload(i);
}else{
window.localStorage.removeItem(hash);
def.success && def.success();
}
}
});
}
getHash(){
const me = this;
const {file,blockCount,chunkSize,userId} = me.def;
return new Promise((resolve, reject) => {
let currentChunk = 0;
const spark = new SparkMD5.ArrayBuffer();
const fileReader = new FileReader();
function loadNext() {
const start = currentChunk * chunkSize;
const end = Math.min(file.size, start + chunkSize);
fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
}
fileReader.onload = e => {
spark.append(e.target.result); // Append array buffer
currentChunk += 1;
if (currentChunk < blockCount) {
loadNext();
} else {
const result = spark.end();
// 如果单纯的使用result 作为hash值的时候, 如果文件内容相同,而名称不同的时候
// 想保留两个文件无法保留。所以把文件名称加上。
const sparkMd5 = new SparkMD5();
sparkMd5.append(result);
sparkMd5.append(file.name);
if(userId){
sparkMd5.append(userId);
}
const hexHash = sparkMd5.end();
resolve(hexHash);
}
};
fileReader.onerror = (e) => {
console.warn('文件读取失败!');
reject(e);
};
loadNext();
}).catch(err => {
console.log(err);
});
}
paused(){
//停止上传
this.paused = true;
}
play(){
//开始上传
this.paused = false;
this.upload(this.current);
}
}
//插件代码结束 const submitBtn = $('#submitBtn');
const fileDom = $('#file')[0];
submitBtn.on('click',() => { // 获取到的files为一个File对象数组,如果允许多选的时候,文件为多个
const files = fileDom.files;
const file = files[0];
if (!file) {
alert('没有获取文件');
return;
}
new FlieSlice({
file:file,
userId:"mannymyu",
progress(obj){
console.log(obj); const form = new FormData();
form.append('file', obj.file);
form.append("name",obj.name);
form.append('count', obj.count);
form.append('index', obj.index);
form.append('size', obj.size);
form.append('hash', obj.hash);
form.append("done",obj.done);
$.ajax({
url: 'http://127.0.0.1:3000',
type: 'post',
data: form,
contentType: false,
processData: false,
success: function (res) {
console.info(res);
//在这里 执行自己的 ajax 上传,执行成功后调用 obj.next 执行下次
if(res.code == 200){
obj.next();
}else{
obj.next(res);
}
},
error: function (error) {
console.info(error);
obj.next(error);
}
}) },
success(){
console.log("success");
}
})
})
</script>
</body>
</html>

  

使用node 的 koa 来完成后端

const os = require('os');
const path = require('path');
const koaBody = require('koa-body');
const Koa = require('koa');
const app = new Koa();
const cors = require('koa2-cors');
const promisify = require("util").promisify;
const fs = require("fs");
const readFile = promisify(fs.readFile);
const fsextra = require('fs-extra')
//递归的创建文件夹
function mkdirs(dirpath) {
if (!fs.existsSync(path.dirname(dirpath))) {
mkdirs(path.dirname(dirpath));
}
fs.mkdirSync(dirpath);
} function createDir(myPath){
fs.existsSync(myPath) == false && mkdirs(myPath);
} //合并文件
function mergeFile(target,arr){
return new Promise((resolve,reject)=>{
function write(curr){
fs.stat(target,function (err,stat) {
if(err){
let WStream = fs.createWriteStream(target);
let readStream = fs.createReadStream(curr);
readStream.pipe(WStream);
run()
}else if(stat.isFile()){
let size = stat.size;
let WSoptions = {
start: size,
flags: "r+"
}
let WStream = fs.createWriteStream(target,WSoptions)
let readStream = fs.createReadStream(curr);
readStream.pipe(WStream);
run()
}else{
reject("不是一个文件");
}
})
}
function run(){
if(arr.length > 0){
write(arr.shift());
}else{
resolve(target);
}
}
run();
});
} const main = async function(ctx) {
const filePaths = [];
const files = ctx.request.files || {};
const params = ctx.request.body; const temp = path.join(__dirname, "tmp" ,params.hash);
const filePath = path.join(temp , `${params.hash}_${params.index}`); createDir(temp);
for (let key in files) {
const file = files[key];
if(Object.prototype.toString.call(file) == '[object Array]'){
ctx.body = {
code:403,
msg:"分片上传不允许多文件上传"
}
return ;
}else{
const reader = fs.createReadStream(file.path);
const writer = fs.createWriteStream(filePath);
reader.pipe(writer);
let staticDir;
console.log(params);
if(params.done == "true"){
//如果已经完成了---合成文件
staticDir = path.join(__dirname, "static",params.name); //最后文件存的地址
var arr = [];
for(var i = 0; i <= params.index; i++){
arr.push(
path.join(temp , `${params.hash}_${i}`)
);
}
try{
let res = await mergeFile(staticDir,arr);
ctx.body = {
code:200,
data: {
done:true,
path:staticDir
},
msg:"成功"
}; }catch(e){
console.log("错误--",e);
ctx.body = {
code:500,
msg:"合并文件错误"
};
} //删除临时文件
fsextra.remove(temp, err => {
if (err) return console.error("删除文件是失败",err) console.log('删除文件成功!')
});
}else{
ctx.body = {
code:200,
data: {
done:false,
path: filePath
},
msg:"成功"
};
} }
return ;
}
}; app.use(cors());
app.use(koaBody({ multipart: true }));
app.use(main);
app.listen(3000);

  

  

js文件分段上传的更多相关文章

  1. js之大文件分段上传、断点续传

    文件夹上传:从前端到后端 文件上传是 Web 开发肯定会碰到的问题,而文件夹上传则更加难缠.网上关于文件夹上传的资料多集中在前端,缺少对于后端的关注,然后讲某个后端框架文件上传的文章又不会涉及文件夹. ...

  2. 兼容好的JS图片上传预览代码

    转 : http://www.codefans.net/articles/1395.shtml 兼容好的JS图片上传预览代码 (谷歌,IE11) <html xmlns="http:/ ...

  3. 兼容各浏览器的js判断上传文件大小

    由于项目需要,在网上找了一个JS判断上传文件大小的程序,经测试兼容IE6-,Firefox10,Opera11.,safari5.,chrome17 <!DOCTYPE html> < ...

  4. 利用ajaxfileupload.js异步上传文件

    1.引入ajaxfileupload.js 2.html代码 <input type="file" id="enclosure" name="e ...

  5. 怎么通过js获取上传的图片信息(临时保存路径,名称,大小)然后通过ajax传递给后端?

    今天在论坛上看到这样一个问题,有必要编辑搜集下. 问题描述:怎么通过js获取上传的图片信息(临时保存路径,名称,大小)然后通过ajax传递给后端 题主用jquery接收 <input name= ...

  6. js获取上传文件内容(未完待续)

    js 获取上传文件的字节数及内容 <div> 上传文件 : <input type="file" name = "file" id = &qu ...

  7. js判断上传文件大小

    下面提供三款网页特效判断上传文件大小哦,这三种方法是现在限制文件上传大小比较好的方法,可以在客户上传文件时限制上传文件大小判断处理<!doctype html public "-//w ...

  8. BootStrap fileinput.js文件上传组件实例代码

    1.首先我们下载好fileinput插件引入插件 ? 1 2 3 <span style="font-size:14px;"><link type="t ...

  9. js文件上传库

    收集了2个与具体UI库和框架无任何耦合的JS文件上传库:支持断点续传.支持npm安装. resumable.js fileapi

随机推荐

  1. ES索引文件和数据文件大小对比——splunk索引文件大小远小于ES,数据文件的压缩比也较ES更低,有趣的现象:ES数据文件zip压缩后大小和splunk的数据文件相当!词典文件tim/tip+倒排doc/pos和cfs文件是索引的大头

    和splunk对比: ES中各个倒排索引文件的分布: 测试说明:ES2.41版本,数据使用500次批量插入,每批数据都不同,大小500条,每条数据50个字段,对应的字符串使用长度为1-10个单词随机生 ...

  2. Windows使用Latex

    目录 安装Texlive 安装TeXstudio 编写简单的文章 教程 安装Texlive 到清华大学开源软件镜像站下载Texlive2019.iso文件 下载之后,如果有光驱就装载,没有的话就解压. ...

  3. Cesium入门-1-展示一个地球

    Cesium 官网教程地址 https://cesium.com/docs/tutorials/getting-started//tutorials/getting-started/ 第一个程序代码: ...

  4. DELPHI解析JSON格式化的日期

    DELPHI解析JSON格式化的日期 json返回的日期是 /Date(1560355200000)/ 这样的格式. 这个1560355200000,是指1970年以后的秒数. DELPHI如何解析这 ...

  5. LDAP的filter查询详解

    转: 等于(EQUAL TO):  =大于等于(Greater than):  >=小于等于(Less than):  <=通配符(wildcard):  *  逻辑运算符:逻辑与(log ...

  6. react组件中返回并列元素的方法

    我们在写react组件的时候,经常会遇到这种问题,在render中return元素只能有一个顶级元素,比如div,假如写成这样就会报错: render(){ return( <div>12 ...

  7. Tosca Connection Validation error:40 - Could not open a connection to SQL Server (不知道怎么解决)

    谁知道下面这个错怎么解决,请给我留言,谢谢. 数据库能正常链接,服务也是 normal running

  8. LC 992. Subarrays with K Different Integers

    Given an array A of positive integers, call a (contiguous, not necessarily distinct) subarray of A g ...

  9. react起步——从零开始编写react项目

    # index.html <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> ...

  10. hadoop目录命令

    下面是经常使用到的,以此记录备忘 1.查看hadoop目录 命令: hadoop fs -ls / 2.创建目录 命令:hadoop fs -mkdir /目录名 3.将文件上传hadoop中(也就是 ...