php 多线程上传,文件分片多线程上传

前两天有人在群里问文件分片上传如何实现,当时没多想就直接说js对文件进行分片,上传分片,后端接受分片,js判断分片上传完成,发起合并请求,后端合并文件即可。后来就用webuploader插件实现了一下,然后他问我可不可以帮他写一个不用插件的分片上传,所以才有了下面的文章。

前端代码

file.html

分片多线程上传--梦中程序员出品

#info {

width: 400px;

height: 200px;

}

.percent_bg {

position: relative;

width: 400px;

height: 20px;

border: 1px solid #ccc;

}

.percent {

position: absolute;

width: 0%;

height: 100%;

background: #0b821c;

}

.percent_num {

position: absolute;

width: 100%;

height: 100%;

text-align: center;

}

文件分片多线程上传,上传成功后返回url

选择文件后自动上传

线程数:

1

2

3

5

10

0%

// 文件分片信息

var blocksInfo = {

"bufferSize": 512 * 1024, // 512K为一片

"blocks": [], // 所有分片文件

"threadNum": 1, // 上传线程数

"filename": "" // 文件名字

};

// 线程信息

var threadInfo = {

"index": 0, // 准备上传的分片索引

"activeThread": 0, // 几个线程在工作

"sendBlocksNum": 0 // 分片上传完成个数

};

// 选择文件触发change事件

$("#file").change(function () {

var file = document.getElementById("file").files[0];

setBlocksInfo(file); // 设置分片信息

// 启动线程

var realThread = Math.min(blocksInfo.threadNum, blocksInfo.blocks.length); // 如果分片数小于线程则只运行分片数的线程

showInfo("分片完成,分了" + blocksInfo.blocks.length + "片,线程数为:" + realThread);

showInfo("------------");

for (var i = 0;i < realThread;i++) {

threadInfo.activeThread++;

// 应该用js的线程插件来控制线程,我们就不用了,我们知道ajax的异步就是用多线程发送请求的,我们使用ajax来模拟多线程,这块虽然函数是单线程,进入事件队列,但是运行到ajax则是多线程了

startThread(i);

}

});

// 设置分片信息

function setBlocksInfo(file)

{

blocksInfo.threadNum = $("#thread_num").val();

blocksInfo.filename = file.name;

var startByte = endByte = 0;

while (true) {

if (endByte + blocksInfo.bufferSize >= file.size) {

endByte = file.size;

} else {

endByte = startByte + blocksInfo.bufferSize;

}

var block = file.slice(startByte, endByte);

blocksInfo.blocks.push(block);

startByte = endByte;

if (endByte >= file.size) {

break;

}

}

}

// 显示运行信息

function showInfo(info)

{

var msg = $("#info").val() + info + "\r\n";

$("#info").val(msg);

var scrollTop = $("#info")[0].scrollHeight;

$("#info").scrollTop(scrollTop);

}

// 线程运行

function startThread(i)

{

if (threadInfo.index >= blocksInfo.blocks.length) {

showInfo("线程" + i + "结束");

threadInfo.activeThread--;

if (threadInfo.activeThread == 0) {

showInfo("------------");

showInfo("分片上传完成,正在处理分片");

combineBlocks(); // 发起合并分片请求

}

return;

}

uploadBlock(i, threadInfo.index); // 使用指定线程上传指定分片

threadInfo.index++; // 准备下一个分片

}

// 上传分片

function uploadBlock(i, index)

{

showInfo("线程" + i + "开始:上传" + index + "分片");

// 组装上传信息,ajax上传文件需要formdata

var fd = new FormData();

fd.append("index", index); // 上传分片序号

fd.append("file", blocksInfo.blocks[index]);

$.ajax({

url: "upload.php",

type: "post",

data: fd,

dataType: "json",

contentType: false, // 文件上传和参数传递请求头和请求体都不一样,ajax设置false就可以

processData: false, // 有文件上传,不对参数序列化

success: function (data) {

threadInfo.sendBlocksNum++; // 设置这个分片已经上传完成

showPercent(); // 上传进度条

showInfo("分片" + index + "上传完成,线程" + i + "即将上传下一个分片");

startThread(i); // 启动线程继续下一个分片上传

}

});

}

// 发起合并分片请求

function combineBlocks()

{

$.ajax({

url: "upload.php",

type: "post",

data: {"act": "combine", "blocks": blocksInfo.blocks.length, "filename": blocksInfo.filename},

dataType: "json",

success: function (data) {

showInfo("分片数据处理完成,任务结束,URL:" + data.url);

}

});

}

// 进度条

function showPercent()

{

var percent = parseInt(threadInfo.sendBlocksNum / blocksInfo.blocks.length * 100);

$(".percent").stop(true, true).animate({"width": percent + "%"}, 10);

$(".percent_num").html(percent + "%");

}

后端代码

upload.php

class Uploader

{

public $tmpPath = __DIR__ . '/tmp/'; // 分片目录

public $filePath = __DIR__ . '/file/'; // 合并分片目录,这俩个目录需手动创建,你也可以使用mkdir创建

public function upload()

{

if (isset($_POST['act']) && $_POST['act'] == 'combine') {

$blocks = $_POST['blocks'];

$filename =time() . $_POST['filename'];

$file = fopen($this->filePath . $filename, 'a+');

for ($i = 0;$i < $_POST['blocks'];$i++) {

$chunkFile = fopen($this->tmpPath . $i, 'r');

fwrite($file, fread($chunkFile, filesize($this->tmpPath . $i)));

fclose($chunkFile);

unlink($this->tmpPath . $i);

}

fclose($file);

$data = [

'url' => "http://" . $_SERVER['HTTP_HOST'] . '/file/' . $filename

];

} else {

$index = $_POST['index']; // 分片索引

move_uploaded_file($_FILES['file']["tmp_name"], $this->tmpPath . $index);

$data = [

'code' => 1

];

}

return json_encode($data);

}

}

echo (new Uploader)->upload();

有疑问可联系QQ305530751

梦中程序员系列教程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值