理清思路:

引入了两个概念:块(block)和片(chunk)。每个块由一到多个片组成,而一个资源则由一到多个块组成

块是服务端的永久数据存储单位,片则只在分片上传过程中作为临时存储的单位。服务端会以约一个月为单位周期性的清除上传后未被合并为块的数据片

实现过程:

将文件分割,分片上传,然后合并

前端核心code:

var fileForm = document.getElementById("file");

var upstartBtn = document.getElementById('upstart');

var stopBtn = document.getElementById('stop');

var startBtn = document.getElementById('restart');

var rate = document.getElementById('rate');

var divlog = document.getElementById('divlog');

//---------------------------

const LENGTH = 1024 * 1024 * 1;

var start = 0;

var end = start + LENGTH;

var blob;

var blob_num = 1;

var is_stop = 0

var file = null;

var md5filename = '';

//-----------------------------

var upload_instance = new Upload();

fileForm.onchange = function()

{

browserMD5File(fileForm.files[0], function (err, md5) { //如果文件大,md5值生成较慢  md5值生成后才能上传处理,自己优化下吧

md5filename = md5;                                  //如果需要刷新后也能断点,可利用cookie记录,自行完善

divlog.innerHTML = '文件md5为:' + md5filename;

});

}

upstartBtn.onclick = function(){

upload_instance.addFileAndSend(fileForm);

}

stopBtn.onclick = function(){

upload_instance.stop();

}

startBtn.onclick = function(){

upload_instance.start();

}

function Upload(){

var xhr = new XMLHttpRequest();

var form_data = new FormData();

//对外方法,传入文件对象

this.addFileAndSend = function(that){

file = that.files[0];

blob = cutFile(file);

sendFile(blob,file);

blob_num += 1;

}

//停止文件上传

this.stop = function(){

xhr.abort();

is_stop = 1;

}

this.start = function(){

sendFile(blob,file);

is_stop = 0;

}

//切割文件

function cutFile(file){

var file_blob = file.slice(start,end);

start = end;

end = start + LENGTH;

return file_blob;

};

//发送文件

function sendFile(blob,file){

var total_blob_num = Math.ceil(file.size / LENGTH);

form_data.append('file',blob);

form_data.append('blob_num',blob_num);

form_data.append('total_blob_num',total_blob_num);

form_data.append('md5_file_name',md5filename);

form_data.append('file_name',file.name);

xhr.open('POST','./index.php',false);

xhr.onreadystatechange = function () {

var progress;

var progressObj = document.getElementById('finish');

if(total_blob_num == 1){

progress = '100%';

}else{

progress = (Math.min(100,(blob_num/total_blob_num)* 100 )).toFixed(2) +'%';

}

console.log('progress-----'+progress);

progressObj.style.width = progress;

rate.innerHTML = progress;

var t = setTimeout(function(){

if(start < file.size && is_stop === 0){

blob = cutFile(file);

sendFile(blob,file);

blob_num += 1;

}else{

//setTimeout(t);

}

},1000);

}

xhr.send(form_data);

}

}

后端code

<?php

class Upload{

private $filepath = './upload'; //上传目录

private $tmpPath; //PHP文件临时目录

private $blobNum; //第几个文件块

private $totalBlobNum; //文件块总数

private $fileName; //文件名

private $md5FileName;

public function __construct($tmpPath,$blobNum,$totalBlobNum,$fileName, $md5FileName){

$this->tmpPath = $tmpPath;

$this->blobNum = $blobNum;

$this->totalBlobNum = $totalBlobNum;

$this->fileName = $this->createName($fileName, $md5FileName);

$this->moveFile();

$this->fileMerge();

}

//判断是否是最后一块,如果是则进行文件合成并且删除文件块

private function fileMerge(){

if($this->blobNum == $this->totalBlobNum){

$blob = '';

for($i=1; $i<= $this->totalBlobNum; $i++){

$blob .= file_get_contents($this->filepath.'/'. $this->fileName.'__'.$i);

}

file_put_contents($this->filepath.'/'. $this->fileName,$blob);

$this->deleteFileBlob();

}

}

//删除文件块

private function deleteFileBlob(){

for($i=1; $i<= $this->totalBlobNum; $i++){

@unlink($this->filepath.'/'. $this->fileName.'__'.$i);

}

}

private function moveFile(){

$this->touchDir();

$filename = $this->filepath.'/'. $this->fileName.'__'.$this->blobNum;

move_uploaded_file($this->tmpPath,$filename);

}

//API返回数据

public function apiReturn(){

if($this->blobNum == $this->totalBlobNum){

if(file_exists($this->filepath.'/'. $this->fileName)){

$data['code'] = 2;

$data['msg'] = 'success';

$data['file_path'] = 'http://'.$_SERVER['HTTP_HOST'].dirname($_SERVER['DOCUMENT_URI']).str_replace('.','',$this->filepath).'/'. $this->fileName;

}

}else{

if(file_exists($this->filepath.'/'. $this->fileName.'__'.$this->blobNum)){

$data['code'] = 1;

$data['msg'] = 'waiting';

$data['file_path'] = '';

}

}

header('Content-type: application/json');

echo json_encode($data);

}

private function touchDir(){

if(!file_exists($this->filepath)){

return mkdir($this->filepath);

}

}

private function createName($fileName, $md5FileName){

return $md5FileName . '.' . pathinfo($fileName)['extension'];

}

}

$upload = new Upload($_FILES['file']['tmp_name'],$_POST['blob_num'],$_POST['total_blob_num'],$_POST['file_name'],$_POST['md5_file_name']);

$upload->apiReturn();

效果展示:

详细代码可参考我写的这篇文章:http://blog.ncmem.com/wordpress/2019/08/12/php%e4%b8%8a%e4%bc%a0%e5%a4%a7%e6%96%87%e4%bb%b6-3/

java大视频上传实现的更多相关文章

  1. java 大文件上传 断点续传 完整版实例 (Socket、IO流)

    ava两台服务器之间,大文件上传(续传),采用了Socket通信机制以及JavaIO流两个技术点,具体思路如下: 实现思路: 1.服:利用ServerSocket搭建服务器,开启相应端口,进行长连接操 ...

  2. java大文件上传解决方案

    最近遇见一个需要上传百兆大文件的需求,调研了七牛和腾讯云的切片分段上传功能,因此在此整理前端大文件上传相关功能的实现. 在某些业务中,大文件上传是一个比较重要的交互场景,如上传入库比较大的Excel表 ...

  3. java+大文件分段上传

    一. 功能性需求与非功能性需求 要求操作便利,一次选择多个文件和文件夹进行上传:支持PC端全平台操作系统,Windows,Linux,Mac 支持文件和文件夹的批量下载,断点续传.刷新页面后继续传输. ...

  4. java+大文件上传解决方案

    众所皆知,web上传大文件,一直是一个痛.上传文件大小限制,页面响应时间超时.这些都是web开发所必须直面的. 本文给出的解决方案是:前端实现数据流分片长传,后面接收完毕后合并文件的思路. 实现文件夹 ...

  5. java大文件上传

    上次遇到这样一个问题,客户上传高清视频(1G以上)的时候上传失败. 一开始以为是session过期或者文件大小受系统限制,导致的错误.查看了系统的配置文件没有看到文件大小限制,web.xml中sees ...

  6. java大附件上传,支持断点续传

    一. 功能性需求与非功能性需求 要求操作便利,一次选择多个文件和文件夹进行上传:支持PC端全平台操作系统,Windows,Linux,Mac 支持文件和文件夹的批量下载,断点续传.刷新页面后继续传输. ...

  7. php实现大视频上传

    本人在2010年时使用swfupload为核心进行文件的批量上传的解决方案.见文章:WEB版一次选择多个文件进行批量上传(swfupload)的解决方案. 本人在2013年时使用plupload为核心 ...

  8. java实现大视频上传

    javaweb上传文件 上传文件的jsp中的部分 上传文件同样可以使用form表单向后端发请求,也可以使用 ajax向后端发请求 1.通过form表单向后端发送请求 <form id=" ...

  9. java+大文件上传下载

    文件上传下载,与传统的方式不同,这里能够上传和下载10G以上的文件.而且支持断点续传. 通常情况下,我们在网站上面下载的时候都是单个文件下载,但是在实际的业务场景中,我们经常会遇到客户需要批量下载的场 ...

随机推荐

  1. WUSTOJ 1274: 喂,这里是帅帅的LCM(Java)

    1274: 喂,这里是帅帅的LCM 题目   在一组数中,找出个数为奇数的数.更多内容点击标题. 分析   其实这种题并不难,做过一次之后,绝对不会错第二次.通过读题可以发现,我们要找的那个数在这一堆 ...

  2. Bloom过滤器

    提出一个问题 在我们细述Bloom过滤器之前,我们先抛出一个问题:给你一个巨大的数据集(百万级.亿级......),怎么判断一个元素是否在此数据集中?或者怎么判断一个元素不在此数据集中? 思考这个问题 ...

  3. SQLSERVER中计算某个字段中用分隔符分割的字符的个数

    比如字段sid中用'|'分割的一些字符   a|b|c|d,需要通过sql查询出字符的个数是4. 可以使用如下脚本: SELECT LEN(sid)-LEN(REPLACE(sid,'|',''))+ ...

  4. 面试经典算法:优先队列,最大堆,堆排序,左偏树Golang实现

    堆排序 使用优先队列-最小/最大堆可实现. 优先队列 优先队列是一种能完成以下任务的队列:插入一个数值,取出最小的数值(获取数值,并且删除).优先队列可以用二叉树来实现,我们称这种为二叉堆. 最小堆 ...

  5. (二十二)JSP基础语法

    一.基础语法 1.1 JSP表达式 JSP脚本表达式(expression)用于将程序数据输出到客户端 语法:<%= 变量或表达式 %> 1 <body> 2 5+3=< ...

  6. (二)Struts.xml文件详解

    一.Struts.xml文件 Struts.xml文件构成 如图,<Struts>标签内共有5个子标签. 1.1 struts-default.xml 查看Struts的内容可知,Stru ...

  7. (三)调用web服务

    (二)发布第一个WebService服务与DSWL文档解析讲解了如何发布一个web服务,本章主要讲述如何调用一个web服务. 这里有三种方式: 使用代理模式调用,需要将服务端的接口类拷贝到客户端中.( ...

  8. JSP开发 路径问题汇总

    //第一种 jsp 表达式 <%=request.getContextPath %> 获取到 web项目名的绝对路径 <!--使用绝对路径的方式引入CSS文件--> <l ...

  9. pytorch自定义网络层以及损失函数

    转自:https://blog.csdn.net/dss_dssssd/article/details/82977170 https://blog.csdn.net/dss_dssssd/articl ...

  10. ES6--JavaScript扩展知识点(let、const、解构)

    一,ES2015(ES6)新增了两个声明变量的关键字:let.const let:只在代码块内{}有效,不可重复声明,不会提前初始化 1.只在代码块内有效 { let a = 1; var b = 2 ...