File, FileReader 和 Ajax 文件上传实例分析(php)


Posted in Javascript onApril 27, 2011

File FileReader 可以干什么?
Ajax文件上传例子
FileReader 对象可以读取文件的 Base64编码数据(readAsDataURL),2进制字符串(readAsBinaryString),文本(readAsText)并且都是异步的。
对了,Email拖拽附件上传就可以利用 FileReader 配合 Ajax 完成。

File 对象
File对象可以从 input[type=file].files 数组,和拖拽事件 event.dataTransfer.files 中获取到。
第一张图是 Chrome 下的 File 对象,第2个图是Firefox下的File对象。Firefox下会多几个方法,注意这里的读取数据方法是同步的。

File, FileReader 和 Ajax 文件上传实例分析(php)

File, FileReader 和 Ajax 文件上传实例分析(php)
FileReader 对象
这是用来读取文件数据的(并且是异步的)。下面是一个简单的代码(file对象用上面的方法取得)

var fileReader = new FileReader(); 
fileReader.onloadend = function(){ 
console.log(this.readyState); // 这个时候 应该是 2 
console.log(this.result); 读取完成回调函数,数据保存在result中 
} 
fileReader.readAsBinaryString(file);// 开始读取2进制数据 异步 参数为file 对象 
//fileReader.readAsDataURL(file); // 读取Base64 
//fileReader.readAsText(file);//读取文本信息

可以运行下面简单的例子(chrome 和 firefox 有效)
<!DOCTYPE html > 
<html> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
<title>html5 File and FileReader</title> 
<link href="html/ui.css" _mce_href="html/ui.css" rel="stylesheet" /> 
</head> 
<body> 
<style type="text/css"><!-- 
.box{background:#f8f8f8;border:1px solid #CCC;padding:10px;-webkit-box-shadow:#000 0px 0px 4px;-moz-box-shadow:#000 0px 0px 4px; 
-webkit-border-radius:2px;font-family: 'Segoe UI', Calibri, 'Myriad Pro', Myriad, 'Trebuchet MS', Helvetica, Arial, sans-serif; 
} 
.bl{ font-weight:700;} 
.dl{ padding:10px; border-top:1px dotted #999;} 
.dl dd{ padding:0; margin:0;} 
.log{border:1px solid #CCC; background:#f8f8f8; width:200px; position:absolute; right:10px; top:10px;} 
.log li{border:1p dotted #CCC;word-wrap:break-word;word-break:break-all; margin:0px; padding:0;} 
.log ul{margin:0px; padding:0; list-style:none;} 
--></style><style type="text/css" _mce_bogus="1"><!-- 
.box{background:#f8f8f8;border:1px solid #CCC;padding:10px;-webkit-box-shadow:#000 0px 0px 4px;-moz-box-shadow:#000 0px 0px 4px; 
-webkit-border-radius:2px;font-family: 'Segoe UI', Calibri, 'Myriad Pro', Myriad, 'Trebuchet MS', Helvetica, Arial, sans-serif; 
} 
.bl{ font-weight:700;} 
.dl{ padding:10px; border-top:1px dotted #999;} 
.dl dd{ padding:0; margin:0;} 
.log{border:1px solid #CCC; background:#f8f8f8; width:200px; position:absolute; right:10px; top:10px;} 
.log li{border:1p dotted #CCC;word-wrap:break-word;word-break:break-all; margin:0px; padding:0;} 
.log ul{margin:0px; padding:0; list-style:none;} 
--></style> 
<div class="box" id="baseInfo"> 
<h2>(把图片拖拽到这里)利用 FileReader 获取文件 base64 编码</h2> 
<div></div> 
</div> 
<div class="log"> 
<ul id="log"> 
</ul> 
</div> 
<script type="text/javascript" ><!-- 
(function(){ 
window.dataValue = 0; 
var html = ' <dl class="dl">\ 
<dd>fileName: $fileName$</dd>\ 
<dd>fileType: $fileType$</dd>\ 
<dd>fileSize: $fileSize$</dd>\ 
<dd><img src="$data$" /></dd>\ 
<dd>fileBase64: <br/>\ 
<div style="width:100%; height:100px;">$fileBase64$</div>\ 
</dd>\ 
</dl>\ 
' 
var log = function(msg){ 
//console['log'](msg); 
document.getElementById('log').innerHTML += '<li>'+ msg +'</li>'; 
} var DP = function(){ 
var defConfig = { 
dropWrap : window 
} 
this.init.apply(this, [defConfig]); 
this.file = null; 
} 
DP.prototype = { 
init:function(args){ 
var dropWrap = args.dropWrap; 
var _this = this; 
dropWrap.addEventListener("dragenter", this._dragenter, false); 
dropWrap.addEventListener("dragover", this._dragover, false); 
dropWrap.addEventListener('drop', function(e){_this.readFile.call(_this,e)} , false); 
log('window drop bind--ok'); 
}, 
_dragenter:function(e){e.stopPropagation();e.preventDefault();}, 
_dragover:function(e){e.stopPropagation();e.preventDefault();}, 
readFile:function(e){ 
e.stopPropagation(); 
e.preventDefault(); 
var dt = e.dataTransfer; 
var files = dt.files; 
for(var i = 0; i< files.length;i++){ 
var HTML = html.slice(); 
HTML = this.writeHeader(files[i], HTML); 
this.read(files[i], HTML); 
} 
}, 
read:function(file, h){ 
var type = file.type; 
var reader = new FileReader(); 
reader.onprogress = function(e){ 
if (e.lengthComputable){ 
log('progress: ' + Math.ceil(100*e.loaded/file.size) +'%') 
} 
}; 
reader.onloadstart = function(e){ 
log('onloadstart: ok'); 
}; 
reader.onloadend = function(e){ 
var _result = e.target.result; 
//console['log'](e.target); 
log('Data URI--ok'); 
var d = document.createElement('div'); 
h = h.replace('$fileBase64$', _result); 
if(/image/.test(file.type)){ 
h = h.replace('$data$',_result); 
} 
d.innerHTML = h; 
document.getElementById('baseInfo').appendChild(d); 
}; 
reader.readAsDataURL(file); // base 64 编码 
return; 
}, 
writeHeader:function(file, h){ 
log(file.fileName + '+' + (file.size/1024)); 
return h.replace('$fileName$', file.fileName).replace("$fileSize$",(file.size/1024)+'KB').replace("$fileType$",file.type); 
} 
} 
new DP(); 
})() 
// --></script> 
</body> 
</html>

如何实现异步文件上传
有了File FileReader 对象的支持,异步文件上传将变得简单。(以前都会把form提交到iframe来实现)
1:取得File对象
2:读取2进制数据
3:模拟HTTP请求,把数据发送出去(这里通常比较麻烦)
在forefox下使用 XMLHttpRequest 对象的 sendAsBinary 方法发送数据;
4:完美实现
遇到的问题
目前仅有 firefox 可以正确上传文件。(Chrome也可以采google.gears上传)
对于从firefox和chrome下读取到的文件数据好像不一样(不知道是否是调试工具的原因)
Chrome以及其他高级浏览器没有 sendAsBinary 方法 只能使用 send 方法发送数据,有可能是上面的原因导致无法正确上传。(经过测试普通文本文件可以正确上传)
如果你有兴趣?
下载这个PHP环境的测试程序,研究下如何实现其他浏览器的文件上传  
Javascript 相关文章推荐
使用js对select动态添加和删除OPTION示例代码
Aug 12 Javascript
js实现日期级联效果
Jan 23 Javascript
js style动态设置table高度
Oct 21 Javascript
文件上传插件SWFUpload的使用指南
Nov 29 Javascript
Html5+jQuery+CSS制作相册小记录
Dec 30 Javascript
Bootstrap下拉菜单Dropdowns的实现代码
Mar 17 Javascript
详解用Node.js写一个简单的命令行工具
Mar 01 Javascript
解决vue项目打包后提示图片文件路径错误的问题
Jul 04 Javascript
vue+axios实现文件下载及vue中使用axios的实例
Sep 21 Javascript
JS实现电话号码的字母组合算法示例
Feb 26 Javascript
webpack4之如何编写loader的方法步骤
Jun 06 Javascript
vuex管理状态 刷新页面保持不被清空的解决方案
Nov 11 Javascript
JavaScript中获取未知对象属性的代码
Apr 27 #Javascript
JavaScript之HTMLCollection接口代码
Apr 27 #Javascript
利用jQuery操作对象数组的实现代码
Apr 27 #Javascript
jquery.cookie.js 操作cookie实现记住密码功能的实现代码
Apr 27 #Javascript
jquery调用asp.net 页面后台的实现代码
Apr 27 #Javascript
jQuery Ajax方法调用 Asp.Net WebService 的详细实例代码
Apr 27 #Javascript
Javascript实现仿WebQQ界面的“浮云”兼容 IE7以上版本及FF
Apr 27 #Javascript
You might like
在Yii框架中使用PHP模板引擎Twig的例子
2014/06/13 PHP
php通过文件头判断格式的方法
2016/05/28 PHP
Thinkphp5.0 框架实现控制器向视图view赋值及视图view取值操作示例
2019/10/12 PHP
网易JS面试题与Javascript词法作用域说明
2010/11/09 Javascript
Jqyery中同等与js中windows.onload的应用
2011/05/10 Javascript
javascript 保存文件到本地实现方法
2012/11/29 Javascript
JavaScript中的连字符详解
2013/11/28 Javascript
Javascript 遍历页面text控件详解
2014/01/06 Javascript
让input框实现类似百度的搜索提示(基于jquery事件监听)
2014/01/31 Javascript
jQuery的load()方法及其回调函数用法实例
2015/03/25 Javascript
js基于面向对象实现网页TAB选项卡菜单效果代码
2015/09/09 Javascript
极易被忽视的javascript面试题七问七答
2016/02/15 Javascript
jQuery插件ContextMenu自定义图标
2017/03/15 Javascript
jQuery EasyUI 为Combo,Combobox添加清除值功能的实例
2017/04/13 jQuery
AngularJS中的promise用法分析
2017/05/19 Javascript
详解Vue中过度动画效果应用
2017/05/25 Javascript
详解vue+css3做交互特效的方法
2017/11/20 Javascript
微信小程序用户自定义模版用法实例分析
2017/11/28 Javascript
vue+iview+less+echarts实战项目总结
2018/02/22 Javascript
详解vuex之store拆分即多模块状态管理(modules)篇
2018/11/13 Javascript
vue-cli3环境变量与分环境打包的方法示例
2019/02/18 Javascript
Vue.extend 登录注册模态框的实现
2020/12/29 Vue.js
在Django的模板中使用认证数据的方法
2015/07/23 Python
Django中的Model操作表的实现
2018/07/24 Python
对pandas中Series的map函数详解
2018/07/25 Python
在 Windows 下搭建高效的 django 开发环境的详细教程
2020/07/27 Python
Python 生成短8位唯一id实战教程
2021/01/13 Python
pycharm 使用tab跳出正在编辑的括号(){}{}等问题
2021/02/26 Python
高街生活方式全球在线商店:AZBRO
2017/08/26 全球购物
DBA的职责都有哪些
2012/05/16 面试题
总经理秘书的岗位职责
2013/12/27 职场文书
代办委托书怎样写
2014/04/08 职场文书
九一八事变演讲稿
2014/09/05 职场文书
机关领导查摆四风思想汇报
2014/09/13 职场文书
入党积极分子对十八届四中全会期盼的思想汇报
2014/10/17 职场文书
MySQL系列之开篇 MySQL关系型数据库基础概念
2021/07/02 MySQL