JS分片上传

开发中遇到的几个问题:
1:js传送文件的数据,无法传送的问题,最后采用了实例化h5的接口,FormData,利用这个构建form表单,进行表单的传送数据,文件
2:遇到了传的问题中,传了一半不传了,是因为设置了timeout的值有点小
3:在用,file_put_contents ,filesize,这两个函数的时候路径没有写对,导致了判断失误的问题
4:FILE_APPEND表示向同一个文件中追加的意思
5:ajax 中timeout的单位为毫秒

file_put_contents($_SERVER['DOCUMENT_ROOT'].'/Crawler/Public/Upload/'.$arr['fileName'],file_get_contents($files['tmp_name']),FILE_APPEND)

// 计算文件大小 size = file.size > 1024 ? file.size / 1024 > 1024 ? file.size / (1024 * 1024) > 1024 ? (file.size / (1024 * 1024 * 1024)).toFixed(2) + 'GB' : (file.size / (1024 * 1024)).toFixed(2) + 'MB' : (file.size / 1024).toFixed(2) + 'KB' : (file.size).toFixed(2) + 'B';


//页面代码
<input type="file" name="slice" id="slice" >
<a href="javascript:void(0);" οnclick="sendForm()">Js File Upload!</a>
<div id="output"><!--  信息存放地  --> </div>

//JS代码
<script type="text/javascript">
    $("#slice").change(function(event) {
        var file = $("#slice")[0].files[0];
        PostFile(file,0);

    });
    //执行分片上传
    function PostFile(file,i){
        var name = file.name,                          //文件名
            size = file.size,                          //总大小shardSize = 2 * 1024 * 1024,
            shardSize = 2 * 1024 * 1024,                //以2MB为一个分片,每个分片的大小
            shardCount = Math.ceil(size / shardSize);  //总片数
        if(i >= shardCount){
            return;
        }
        //console.log(size,i+1,shardSize);  //文件总大小,第一次,分片大小//
        var start = i * shardSize;
        var end = start + shardSize;
        var packet = file.slice(start, end);  //将文件进行切片
        /*  构建form表单进行提交  */
        var form = new FormData();
        form.append("data", packet); //slice方法用于切出文件的一部分
        form.append("lastModified", file.lastModified); //最后的额修改时间
        form.append("name", name);
        form.append("totalsize", size);
        form.append("total", shardCount); //总片数
        form.append("index", i + 1); //当前是第几片
        $.ajax({
            url: "__CONTROLLER__/upload",
            type: "POST",
            data: form,
            //timeout:"10000",
            async: true, //异步
            dataType:"json",
            processData: false, //很重要,告诉jquery不要对form进行处理
            contentType: false, //很重要,指定为false才能形成正确的Content-Type
            success: function (msg) {
                console.log(msg);
                /*  表示上一块文件上传成功,继续下一次  */
                if (msg.status == 201) {
                    form = '';
                    i++;
                    PostFile(file, i);
                } else if (msg.status == 502) {
                    form = '';
                    /*  失败后,每2秒继续传一次分片文件  */
                    setInterval(function () { PostFile(file, i) }, 2000);
                } else if (msg.status == 200) {
                    console.log("上传成功");
                } else if (msg.status == 500) {
                    console.log('第'+msg.i+'次,上传文件有误!');
                } else {
                    console.log('未知错误');
                }
            }
        })
    }
</script>

//服务器端代码
if($_POST){
    $files = $_FILES['data'];
    $arr['i'] = $_POST['index'];
    $arr['shardCount'] = $_POST['total'];
    $arr['totalsize'] = $_POST['totalsize'];
    $arr['fileName'] = $_POST['name'];
    if($files['error'] > 0){
        $arr['status'] = 500;
        exit(json_encode($arr));
    }
    if($files['error'] == 0){
        /*  检测第一次上传的时候已经有同文件时,删除原来的文件  */
        if ($arr['i'] == 1 && is_file('/Public/Upload/'. $arr['fileName']) && filesize($_SERVER['DOCUMENT_ROOT'].'/Crawler/Public/Upload/'. $arr['fileName']) == $arr['totalsize']) {
            unlink($_SERVER['DOCUMENT_ROOT'].'/Crawler/Public/Upload/'. $arr['fileName']);
        }
        // 否则继续追加文件数据
        if (!file_put_contents($_SERVER['DOCUMENT_ROOT'].'/Crawler/Public/Upload/'.$arr['fileName'],file_get_contents($files['tmp_name']),FILE_APPEND)) {
            $arr['status'] = 501;
            exit(json_encode($arr));
        }
        // 在上传的最后片段时,检测文件是否完整(大小是否一致)
        if ($arr['i'] == $arr['shardCount']) {
if(filesize($_SERVER['DOCUMENT_ROOT'].'/Crawler/Public/Upload/'. $arr['fileName']) == $arr['totalsize']){
    $arr['status'] = 200;
}else{
    $arr['status'] = 501;
}
exit(json_encode($arr));
        }
        $arr['status'] = 201;
        exit(json_encode($arr));
    }else{
        $arr['status'] = 502;
        exit(json_encode($arr));
    }
}else{
    $this->display();
}



附件1:upload.html,
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JS分片上传-极速上传</title>
</head>
<body>
    <input type="file" name="slice" id="slice" >
    <a href="javascript:void(0);" οnclick="sendForm()">Js File Upload!</a>
    <div id="output"><!--  信息存放地  --> </div>
<br/>
</body>
<script src="__PUBLIC__/js/jquery-1.8.3.min.js"></script>
<script type="text/javascript">
    $("#slice").change(function(event) {
        var file = $("#slice")[0].files[0];
        PostFile(file,0);


    });
    //执行分片上传
    function PostFile(file,i){
        var name = file.name,                           //文件名
            size = file.size,                           //总大小shardSize = 2 * 1024 * 1024,
            shardSize = 2 * 1024 * 1024,                //以2MB为一个分片,每个分片的大小
            shardCount = Math.ceil(size / shardSize);   //总片数
        if(i >= shardCount){
            return;
        }
        //console.log(size,i+1,shardSize);  //文件总大小,第一次,分片大小//
        var start = i * shardSize;
        var end = start + shardSize;
        var packet = file.slice(start, end);  //将文件进行切片
        /*  构建form表单进行提交  */
        var form = new FormData();
        form.append("data", packet); //slice方法用于切出文件的一部分
        form.append("lastModified", file.lastModified); //最后的额修改时间
        form.append("name", name);
        form.append("totalsize", size);
        form.append("total", shardCount); //总片数
        form.append("index", i + 1); //当前是第几片
        $.ajax({
            url: "__CONTROLLER__/upload",
            type: "POST",
            data: form,
            //timeout:"10000",  //超时10秒
            async: true, //异步
            dataType:"json",
            processData: false, //很重要,告诉jquery不要对form进行处理
            contentType: false, //很重要,指定为false才能形成正确的Content-Type
            success: function (msg) {
                console.log(msg);
                /*  表示上一块文件上传成功,继续下一次  */
                if (msg.status == 201) {
                    form = '';
                    i++;
                    PostFile(file, i);
                } else if (msg.status == 502) {
                    form = '';
                    /*  失败后,每2秒继续传一次分片文件  */
                    setInterval(function () { PostFile(file, i) }, 2000);
                } else if (msg.status == 200) {
                    console.log("上传成功");
                } else if (msg.status == 500) {
                    console.log('第'+msg.i+'次,上传文件有误!');
                } else {
                    console.log('未知错误');
                }
            }
        })
    }




</script>
</html>

附件2:SliceUploadController.class.php
<?php
namespace Home\Controller;
use Think\Controller;
class SliceUploadController extends Controller {
    /*
     * JS预览
     * @author 阿旺
     * */
    public function index(){
        $this->display();
    }


    /*
     * 分片上传demo
     * @author 阿旺
     * */
    public function upload(){
        if($_POST){
            $files = $_FILES['data'];
            $arr['i'] = $_POST['index'];
            $arr['shardCount'] = $_POST['total'];
            $arr['totalsize'] = $_POST['totalsize'];
            $arr['fileName'] = $_POST['name'];
            if($files['error'] > 0){
                $arr['status'] = 500;
                exit(json_encode($arr));
            }
            if($files['error'] == 0){
                /*  检测第一次上传的时候已经有同文件时,删除原来的文件  */
                if ($arr['i'] == 1 && is_file('/Public/Upload/'. $arr['fileName']) && filesize($_SERVER['DOCUMENT_ROOT'].'/Crawler/Public/Upload/'. $arr['fileName']) == $arr['totalsize']) {
                    unlink($_SERVER['DOCUMENT_ROOT'].'/Crawler/Public/Upload/'. $arr['fileName']);
                }
                // 否则继续追加文件数据
                if (!file_put_contents($_SERVER['DOCUMENT_ROOT'].'/Crawler/Public/Upload/'.$arr['fileName'],file_get_contents($files['tmp_name']),FILE_APPEND)) {
                    $arr['status'] = 501;
                    exit(json_encode($arr));
                }
                // 在上传的最后片段时,检测文件是否完整(大小是否一致)
                if ($arr['i'] == $arr['shardCount']) {
                    $arr['status'] = 200;
                    exit(json_encode($arr));
                }
                $arr['status'] = 201;
                exit(json_encode($arr));
            }else{
                $arr['status'] = 502;
                exit(json_encode($arr));
            }
        }else{
            //echo "1";die;
            $this->display();
        }


    }


    /*
     * JS断点上传
     * @author 阿旺
     * */
    public function breakpoint($file_path = '') {
        if ($_POST) {
            $speed = 1024;//此参数为下载最大速度
            $pos = strrpos($file_path, "/");
            $file_name = substr($file_path, $pos + 1);
            $file_size = filesize($file_path);
            $ranges = $this->getRange($file_size);
            $fh = fopen($file_path, "rb");
            header('Cache-control: public');
            header('Content-Type: application/octet-stream');
            header('Content-Disposition: attachment; filename=' . $file_name);
            if ($ranges != null) {
                header('HTTP/1.1 206 Partial Content');
                header('Accept-Ranges: bytes');
                header(sprintf('Content-Length: %u', $ranges['end'] - $ranges['start']));
                header(sprintf('Content-Range: bytes %s-%s/%s', $ranges['start'], $ranges['end'], $file_size));
                fseek($fh, sprintf('%u', $ranges['start']));
            } else {
                header("HTTP/1.1 200 OK");
                header(sprintf('Content-Length:%s', $file_size));
            }
            while(!feof($fh)) {
                fread($fh, round($speed*1024, 0));
                ob_flush();
                //sleep(1);
            }
        } else {
            $this->display();
        }
    }


    /**
     * 获取header range信息
     * @param  int   $file_size 文件大小
     * @return Array
     * */
    private function getRange($file_size){
        if(isset($_SERVER['HTTP_RANGE']) && !empty($_SERVER['HTTP_RANGE'])){
            $range = $_SERVER['HTTP_RANGE'];
            $range = preg_replace('/[\s|,].*/', '', $range);
            $range = explode('-', substr($range, 6));
            if(count($range)<2){
                $range[1] = $file_size;
            }
            $range = array_combine(array('start','end'), $range);
            if(empty($range['start'])){
                $range['start'] = 0;
            }
            if(empty($range['end'])){
                $range['end'] = $file_size;
            }
            return $range;
        }
        return null;
    }
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的 JavaScript 分片代码示例: ```javascript const CHUNK_SIZE = 1024 * 1024; // 每个分片大小为1MB,可以根据实际情况进行调整 function uploadFile(file) { const totalChunks = Math.ceil(file.size / CHUNK_SIZE); // 计算总共需要上分片数 let uploadedChunks = 0; // 已上分片数 // 生成一个 Promise 对象,用于上指定的分片 function uploadChunk(chunkIndex) { return new Promise((resolve, reject) => { const startByte = chunkIndex * CHUNK_SIZE; const endByte = Math.min((chunkIndex + 1) * CHUNK_SIZE, file.size); const xhr = new XMLHttpRequest(); xhr.open("PUT", "/upload", true); xhr.setRequestHeader("Content-Type", "application/octet-stream"); xhr.setRequestHeader("X-Chunk-Index", chunkIndex); xhr.setRequestHeader("X-Total-Chunks", totalChunks); xhr.onload = () => { if (xhr.status >= 200 && xhr.status < 300) { resolve(); } else { reject(xhr.statusText); } }; xhr.onerror = () => reject(xhr.statusText); xhr.send(file.slice(startByte, endByte)); }); } // 串行上所有分片 function uploadAllChunks() { if (uploadedChunks >= totalChunks) { // 所有分片完成 alert("上完成!"); return; } uploadChunk(uploadedChunks) .then(() => { uploadedChunks++; uploadAllChunks(); }) .catch(error => { console.error(`上第 ${uploadedChunks} 个分片时遇到错误:${error}`); }); } uploadAllChunks(); } ``` 在上述代码中,我们定义了 `CHUNK_SIZE` 常量表示每个分片的大小,然后根据文件大小计算出总共需要上分片数。`uploadChunk` 函数用于上指定分片,它返回一个 Promise 对象表示上结果。`uploadAllChunks` 函数则用于串行上所有分片,每上一个分片就调用一次 `uploadChunk` 函数,如果上成功则继续上下一个分片,否则记录错误信息并停止上。最后,我们调用 `uploadAllChunks` 函数开始上所有分片。 需要注意的是,上述代码中我们使用了 XMLHttpRequest 对象来进行分片,因此需要在服务端正确处理上请求。具体实现方式可以参考使用其他方法上整个文件的代码。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值