关于ajax分段上传文件实例~

本来打算写的勤快一点的,谁知道最近好忙啊,忙着应聘的事情,这里突然想提一下自己的历程

自己现在是一只大三狗,高中三年是玩过去了,上了一所省内普通的不能再普通的二本。不过在大学里还算的上勤奋,大一上在学生会搅搅水,大一下就开始在学校网络中心里面干活,网络维护是工作,编程是兴趣,基本上每天网络中心寝室两点一线,所以说还算得上勤奋。不过现在我自己算是明白,很多事情不是勤奋就好了的,方法不对,真的是事倍功半。自己之前学习东西都是瞎倒腾,看书,看视频,记笔记,写demo。看起来稀疏平常,但是自己缺点在于太好高骛远了。

想起来一件好玩的事情,曾经网络中心内部需要搭建一个论坛,自己当时逮到就写,打算写一个在线交流的。想法很好是吧,可是当时的我压根就不知道web socket……我是如何实现的呢,无时无刻的不在用ajax。成功倒也成功了,只是觉得不是很值得,ajax确实可以一定的模拟web实时,不过会用尝试一下就行,真的要拿来做聊天室,写着累,别人用着也不方便,举个栗子就是判断别人在不在线。

这段事件因为招聘复习基础,发现了自己太多太多不牢固的地方,以前的自己太过轻浮,现在回炉重造,任何东西都努力自己尝试尝试,自己加上一些想法,然后发表出来。就好比这次的Ajax分段上传文件。

——————————————————————————————————————————————————————————————————————————————

回归正题,实现声明,UI无美化,美观强迫症的我就对不起你们了~

html部分代码

<div id="wrap">
        <form method="post" action="./test.php" enctype="multipart/form-data">
            <input type="file" name="file" id="f"></input>
        </form>
</div>

最简单的布局了,就是绕着一个input type='file'空间展开的,因为一切随简,所以没有加multiple="true"

 1 window.onload = function(){
 2     var oFile = document.getElementById('f');
 3     
 4     var fileSplitSize = 1024 * 1024;  //文件分段大小1M
 5     
 6     oFile.addEventListener('change', function(e){
 7         var files = this.files;
 8         
 9         var file = files[0];  //获得file对象
10         
11         var size = file.size,
12             start = 0;
13 
14         var funUpload = function(){
15 
16             var data = new FormData();  //利用FormData对象模拟表单
17             
18             //data.append('name', encodeURIComponent(file.name));  //Ajax如果用GET方法必须要编码再传递,不过POST我测试出来不需要也可以诶
19             data.append('name', file.name);
20             data.append('file', file.slice(start, start + fileSplitSize));  //核心切割file文件,下面详细解释①
21             data.append('start', '' + start);
22             
23             var xhr = new XMLHttpRequest();  //XMLHttpRequest 2.0对象
24             
25             xhr.open('post', './test.php', true);
26             //xhr.setRequestHeader('Content-Type', 'multipart/form-data');  //这里千万不要加这句话,下面有原因②
27             xhr.setRequestHeader('X_Requested_With', location.href.split("/")[3].replace(/[^a-z]+/g, '$'));
28             xhr.send(data);
29             
30             xhr.onreadystatechange = function(){
31                 if(xhr.readyState == 4){
32                     if(xhr.status == 200){
33                         if(start + fileSplitSize >= size){
34                             alert(xhr.responseText);
35                         }else{
36                             alert('一次上传成功');
37                             start += fileSplitSize;
38                             funUpload();
39                         }
40                     }
41                 }
42             }
43         }
44         funUpload();
45         
46     }, false);
47 }

看①

file对象继承Blob对象,不知道这两个对象的自行百度我就不解释了,算了还是贴一个图吧~

其实此时file.slice(start, start + fileSplitSize)得到的结果是Blob对象,将它作为模拟的表单的file传递给服务器端

再看②

这个一定要注意,两张图就可以解释原因了

如果你加了xhr.setRequestHeader('Content-Type', 'multipart/form-data');

然后上传文件就会失败了,缺少boundary这分隔符

再让我们看看正确的样子

本人感觉这是一个坑。。因为本人栽进去一次。。希望别人注意

前端部分完结,下面是PHP的,很简单

define('ROOT', '.');

$filename = ROOT . '/' . iconv('utf-8', 'gbk', $_POST['name']);  //转码这里千万要注意,否则中文名的话系统就会乱码①
        
if($_POST['start'] == 0){
    
    $fp = fopen($filename, "w+");
    
    file_put_contents($filename, file_get_contents($_FILES[$name]['tmp_name']), FILE_APPEND);
    
    fclose($fp);
    
}else{
    
    file_put_contents($filename, file_get_contents($_FILES[$name]['tmp_name']), FILE_APPEND);
    
}

echo $filename;

看①

通常我们的PHP脚本文件要么是Unicode(utf8)或者是ANSI(gbk),gbk兼容gb2312

如果是Unicode编码(utf8),代码里的中文和系统是两种不同的编码,与系统打交道时,如创建中文名称的文件、文件夹等,需要转换编码。

如果是ANSI编码(gbk、gb2312),代码里的中文和系统是系统的编码,不需要转换编码。

结语:其实这个分段传输可拓展性还是很高的啊,比如断点续传等等~我在这里就不演示啦~

最近在好好地读ECMA5,正确整理一点资料早点发出来~

原文地址:https://www.cnblogs.com/constructor/p/4415859.html