本来打算写的勤快一点的,谁知道最近好忙啊,忙着应聘的事情,这里突然想提一下自己的历程
自己现在是一只大三狗,高中三年是玩过去了,上了一所省内普通的不能再普通的二本。不过在大学里还算的上勤奋,大一上在学生会搅搅水,大一下就开始在学校网络中心里面干活,网络维护是工作,编程是兴趣,基本上每天网络中心寝室两点一线,所以说还算得上勤奋。不过现在我自己算是明白,很多事情不是勤奋就好了的,方法不对,真的是事倍功半。自己之前学习东西都是瞎倒腾,看书,看视频,记笔记,写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,正确整理一点资料早点发出来~