`
yiminghe
  • 浏览: 1433201 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

浏览器文件操作

阅读更多

一直以来客户端文件操作在浏览器中由于安全原因而很少涉及,之前主要有判断文件大小以及缩略图等应用。


基本应用:

 

1.判断文件大小

   ie 中可以使用 activeX (Scripting.FileSystemObject) 来获取输入框选择文件的大小,但是由于受安全设置而并不实用。其他标准浏览器可以使用 html file api 提供的接口直接获取文件大小:

 

<input id='f' type='file'/>

alert(document.getElementById('f').files[0].size);

 

2.缩略图预览

 

   ie < 7 中的 img src 可以直接设置本地地址,进行预览。

 

<img src='c:/test.jpg'/>

 

   这时还可以在 img onload 后通过 img.fileSize 来获得图片的大小.

 

   ie 7,8,9 提升了安全,禁掉了img的本地地址,但对于滤镜 而没有限制:

 

  <DIV ID="oDiv" STYLE="position:relative; height:250px; width:250px;         
        filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(
            src='c:/workshop/graphics/earglobe.gif', sizingMethod='scale');" >
        </DIV>

 

但这时就无法通过 img 标签获取图片的大小了.

 

 

PS : ie8,9 有 fakepath 现象 : 默认在非信任域有个设置项设严格了:

 

 

导致不能直接取 file input 的值了,需要使用 range 迂回:

 

<DIV ID="oDiv" STYLE="position:relative; height:250px; width:250px;         
        filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(
            src='d:/pic/', sizingMethod='scale');" >
        </DIV>
  	<input type='file' onchange="ok(this);">
  	function ok(self){
  			self.select(); 
  			var path=document.selection.createRange().text;
  			document.getElementById("oDiv").style.filter=
  			"progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+path+"', sizingMethod='scale');";
  	}
 

 

 

chrome, firefox 等标准浏览器,结合 datauri 以及 filereader api ,可以直接读取文件的 datauri 数据设置给 img 标签即可:

 

<input id='f' type='file'/>
//注意:chrome本地协议不行,必须http://xx/x.html
var r=new FileReader();
var file=document.getElementById('f').files[0],
      img=document.getElementById('img1');
r.onload=function(ev){		    	
   img.src = ev.target.result;
};
r.readAsDataURL(file);

 

 

PS: chrome本地直接打开不行!wierd 。IE9 不支持 FileReader,还好是继续支持滤镜,网上流传的 ff 特有 getAsDataURL 做法已经无参考必要了 ,现在可以全平台支持无上传客户端预览了!

 

上传预览 demo @ googlecode

 

已知问题:

 

1. ie fakepath 情况下可能会出现 createRange() 获取真实地址时 ie 抛出拒绝访问(access denied)错误,目前无法解决。

 

2. safari 没有 filereader 接口,无法进行预览.

 

综合解决方案

 

和后端配合,如果 ie 下路径包含 c:\fakepath\  或 safari 下则先通过无刷新文件上传到服务器返回服务器代理地址预览.

 

 

更复杂的应用:

 

gmail 以及 google doc 都支持在 firefox 以及 chrome 下从桌面直接拖动照片到指定区域实现上传功能,特别是在编辑区域中可以拖动图片到任意位置,达到了和本地程序相似的用户体验,减少操作步鄹。这次也尝试下实现这个功能。

 

ps: gmail 问题:

 

gmail 和 google doc 不是同一套编辑系统,closure editor 弱了不少,比如不支持 firefox 在编辑区域内拖放上传:

 

 

 

chrome 虽然支持在编辑区域拖放上传,但是插入位置不对,并不是鼠标drop位置,下面会说道:在 chrome 下这个精确位置的确很难取到!

 

 

 

规范:

 

涉及3方面的规范

 

1. drag and drop : 可以阻止浏览器的默认行为以及获得用户从桌面拖放而来的文件句柄。

 

2. fileapi : 对用户主动选择文件的操作 api

 

3. XMLHttpRequest2 : 传输二进制数据而不是字符串。

 

 

实现:

 

1.阻止系统默认行为

 

   阻止拖动区域的相关拖动事件,防止浏览器直接打开拖放文件,更进一步可以设置拖放鼠标图标等:

 

Event.on(document, "dragenter dragover", function(ev) {
        ev.halt();
});
Event.on(document, "drop", function(ev) {
        ev.halt();
});

 

具体可参考 Drag Operations@MDC (非常难用的api,除了文件拖放上传其他地方还是用类库模拟 的好)

 

注意:

 

1. chrome 只要 dragover preventDefault 就可以触发drop 事件,并且阻止浏览器默认事件(打开该文件).

 

2. firefox 必须 dragover preventDefault 并且 stopPropagation 才能触发 drop 事件,而进一步 drop preventDefault 并且 stopPropagation 才能阻止浏览器默认事件(打开该文件).

 

2.获取插入点

 

  firefox 中当拖放图片到可编辑区域(iframe,而不是contentEditable=true的元素)时会自动插入生成的img标签,地址为图片的本地地址

 

<img _moz_dirty='' src='c:/xx.jpg' />
 

 则上传后只要替换该元素即可,需要注意的是必须异步在 drop 事件触发后获取该元素,在 drop 事件处理函数中同步取不到刚刚自动插入的元素。

 

其实只要记下该插入元素的父亲及下一个兄弟节点即可,然后替换插入元素为 loading 图标。

 

if (UA.gecko) {
            S.all("img", document.body).each(function(el) {
                if (el[0].hasAttribute("_moz_dirty")) {
                    archor = el[0].nextSibling;
                    ap = el[0].parentNode;
                    el.remove();
                }
            });
        }


updated 2010-12-26 :

 

最好使用 DOMNodeInserted 事件,在拖放中监听:

 

Event.on(document, "DOMNodeInserted", nodeInsert);

 

记录是否插入的是本地文件,避免干扰页面内拖放功能:

 

function nodeInsert(ev) {
        var oe = ev.originalEvent;
        var t = oe.target;
        if (S.DOM._4e_name(t) == "img" && t.src.match(/^file:\/\//)) {
            inserted[t.src] = t;
        }
    }

 

drop 时去除自动插入的图片,并找出插入点:

 

/**
         * firefox 会自动添加节点
         */
        if (!S.isEmptyObject(inserted)) {

            S.each(inserted, function(el) {
                if (S.DOM._4e_name(el) == "img") {
                    archor = el.nextSibling;
                    ap = el.parentNode;
                    S.DOM._4e_remove(el);
                }
            });
            inserted = {};
        }
 

 

 

chrome 中不会自动插入img 元素,并且拖放过程中编辑光标并不会随之变化,因此选择区 range 也不会随拖动而变化,那么只有利用拖动时的鼠标位置信息,利用 elementfrompoint 来获得鼠标所处元素,但是由于文本并不是元素,那么不可避免会没有 firefox 下那么精确,google doc 则是完全自主实现光标定位,难度过大。

 

//空行里拖放肯定没问题,其他在文字中间可能不准确
            ap = document.elementFromPoint(ev.clientX, ev.clientY);
            archor = ap.lastChild;
 

 

然后就可以根据定位信息来插入loading图片,下一步就是上传本地图片到服务器从而替换元素为服务器端图片地址。

 

var img = new Node("<img " +
                "src='" +
                 "loading.gif" + "'" +
                "/>");
            ap.insertBefore(img, archor);

 

 

拖放定位 demo

 

3.文件 xhr 上传

 

一般所说的文件异步上传是指通过提交 form 到 iframe 并监听状态来实现,而通过拖放上传的话由于不涉及 form,则不能使用以上方法,不过标准浏览器实现了 XMLHttpRequest2 ,可以和服务器端进行二进制传输,手工构建 multipart/form-data 格式的 post 信息,就能实现文件上传了。

 

主要用到:

 

filereader : 可以通过异步读取用户选择文件的二进制信息(raw data)

 

 var reader = new FileReader();
reader.onload = function(ev) {
         //文件原始数据字符串,高8位为0   
         var fileData = ev.target.result;
};
reader.readAsBinaryString(file);

 由于 javascript 字符为16位,则在表达单字节二进制的字符中,高8位为0,另外chrome不支持 addEventLister 来监听 load 事件。

 

构建 multipart/form-data 格式的提交信息:完全依据 rfc2388 (ietf ),声明任意边界字符串 boundary,区别对待文件以及普通表单数据:

 

//文件数据
var body = "\r\n--" + boundary + "\r\n";
body += "Content-Disposition: form-data; name=\"" + fileInput + "\"; filename=\"" + encodeURIComponent(fileName) + "\"\r\n";
body += "Content-Type: " + (file.type || "application/octet-stream") + "\r\n\r\n";
//文件原始数据
body += fileData + "\r\n";


//普通表单域数据
for (var p in serverParams) {
    if (serverParams.hasOwnProperty(p)) {
        body += "--" + boundary + "\r\n";
        body += "Content-Disposition: form-data; name=\"" + p + "\"\r\n\r\n";
        body += serverParams[p] + "\r\n";
    }
}
body += "--" + boundary + "--";
 

设置请求的 content-type

 

xhr.setRequestHeader("Content-Type",
                "multipart/form-data, boundary=" + boundary);
 

最后通过 firefox 的私有api:sendAsBinary,直接发送二进制数据

 

 xhr.sendAsBinary("Content-Type: multipart/form-data; boundary=" +
                boundary + "\r\nContent-Length: " + body.length
                + "\r\n" + body + "\r\n");
 

需要注意的是 sendAsBinary 为 firefox 私有方法,不过对于 chrome ,可以通过构建 blob数据 ,通过标准的 send 来达到同样的效果:

 

if (!XMLHttpRequest.prototype.sendAsBinary) {
        XMLHttpRequest.prototype.sendAsBinary = function(datastr, contentType) {
            var bb = new BlobBuilder();
            var len = datastr.length;
            var data = new Uint8Array(len);
            for (var i = 0; i < len; i++) {
                data[i] = datastr.charCodeAt(i);
            }
            bb.append(data.buffer);
            this.send(bb.getBlob(contentType));
        }
    }
 

 

当 xhr 返回时,将服务器图片地址替换掉loading图标即可:

 

xhr.onreadystatechange = function() {
                if (xhr.readyState == 4) {
                    if (xhr.status == 200 ||
                        xhr.status == 304) {
                        if (xhr.responseText != "") {
                            var info = S.JSON.parse(xhr.responseText);
                            img.src = info.imgUrl;
                        }
                    }
                }
            };

 

对于后端程序来说,该请求和直接form提交没有任何区别.

 

refer :

 

使用input来达到指定区域拖放上传:

http://www.thecssninja.com/javascript/gmail-upload

 

拖放的简明应用介绍:

http://html5doctor.com/native-drag-and-drop/

 

拖放上传的权威例子以及相关api

https://developer.mozilla.org/en/using_files_from_web_applications

 

https://developer.mozilla.org/En/DragDrop/Drag_Operations

https://developer.mozilla.org/En/DragDrop/DataTransfer

https://developer.mozilla.org/en/DOM/FileReader

 

 

一个成熟的跨平台拖放上传组件

http://uploader.rickylab.co.cc/

 

The File API has changed


Drag and drop file uploading using JavaScript

 

 

 

 

 

 

 

  • 大小: 5.4 KB
  • 大小: 46.3 KB
分享到:
评论
4 楼 yiminghe 2010-12-24  
kjah 写道

getAsDataURL()只有ff支持吧?webkit和opera都不行吧,是不是还有要什么条件?
以下测试代码:


不好意思,没仔细测,这个搞错了,已修正,应该是 filereader 的 api

<html>
 <head>
  <title> new document </title>
<SCRIPT>

	function fn(){
		//注意:chrome本地协议不行,必须http://xx/x.html
		var r=new FileReader();
		var file=document.getElementById('f').files[0],
		    img=document.getElementById('img1');
		    
		    r.onload=function(ev){		    	
		    	img.src = ev.target.result;
		    };
		    r.readAsDataURL(file);
		
	}
</SCRIPT>
 </head>
 <body>
  <img id="img1"/>
  <input id='f' type='file'/>
  <input type="button" value="test" id="cc" onclick="fn()"/>
 </body>
</html>

3 楼 kjah 2010-12-24  

引用
chrome,firefox 等标准浏览器,结合 datauri 以及 file api ,可以直接读取文件的 datauri 数据设置给 img 标签即可:


getAsDataURL()只有ff支持吧?webkit和opera都不行吧,是不是还有要什么条件?
以下测试代码:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
 <head>
  <title> new document </title>
<SCRIPT LANGUAGE="JavaScript">
<!--
	function fn(){
		var file=document.getElementById('f').files[0],
		    img=document.getElementById('img1');   
		img.src = file.getAsDataURL();
	}
//-->
</SCRIPT>
 </head>
 <body>
  <img id="img1"/>
  <input id='f' type='file'/>
  <input type="button" value="test" id="cc" onclick="fn()"/>
 </body>
</html>
2 楼 yiminghe 2010-12-22  
i_love_sc 写道
看了之后除了惊讶就是佩服,不知道博主的学习方法是什么,如何能够从一个问题到寻找答案的?

呵呵,就是传统的

自底向上
从实现到抽象
从实践到理论
1 楼 i_love_sc 2010-12-22  
看了之后除了惊讶就是佩服,不知道博主的学习方法是什么,如何能够从一个问题到寻找答案的?

相关推荐

    易语言浏览器操作模块源码

    易语言浏览器操作模块源码。易语言浏览器操作模块源码。分类:。初级教程。关键字:。易语言例程 超文本浏览框 易语言教程 易语言模块 文本文件 易语言源码。易语言浏览器操作模块源码例程程序结合易语言超文本浏览...

    Ghost 浏览器 ghost 文件浏览器

    Ghost 浏览器 可以对.gho文件进行提取编辑操作

    e语言-易语言浏览器操作模块

    易语言浏览器操作模块源码易语言浏览器操作模块源码分类:初级教程关键字:易语言例程 超文本浏览框 易语言教程 易语言模块 文本文件 易语言源码易语言浏览器操作模块源码例程程序结合易语言超文本浏览框支持库,...

    使用c++编写WebAssembly在浏览器端操作Excel demo

    使用C++,cmake编写 WebAssembly在浏览器端操作Excel 的一个demo 代码为博客实例代码 https://blog.csdn.net/weixin_44305576/article/details/125545900

    浏览器查看PDF文件(JS)

    通过jQuery,可以在浏览器查看PDF文件,简单,易操作,

    [原创]FSO文件浏览器

    这是一个利用FSO集合对象编写的FSO文件浏览器(如果你非要...新建、删除、改名、复制、移动等基本文件操作 文本文件编辑 Stream方式文件下载 精简优化的无组件上传 文件打包/解包,一个文件夹可以完整地被打包/解包

    文件管理、浏览器

    文件管理/浏览器本软件为标准Windows32位应用程序。可以对本地以及局域网的计算机中的文件进行一些如更名、移动、复制和删除等操作。还可以对相关文件进行预览、查看,比如像数字图片、网页、数字音乐以及一些Word,...

    实例23_文件操作_启动浏览器.rar_实例文件操_文件浏览器

    实例23_文件操作_启动浏览器

    FileloupeforMac(文件浏览器)v1.4.4苹果电脑版

    Fileloupe for Mac (文件浏览器)是一款运行在mac平台上的文件预览工具,支持对各种文件的集中显示,移动,复制和删除等操作都不会对原文件产生任何的影响,支持对各种文件的集中显示,移动,复制和删除等操作都不会对原...

    ES 文件浏览器 ES File Explorer 4.2.4.5 中文免费版.zip

    ES 文件浏览器是一款多功能的手机文件/程序/进程管理器,可以在手机、电脑、远程和蓝牙间浏览管理文件。是一个功能强大的免费的本地和网络文件管理器和应用程序管理器。适用2.0以上Android机型。ES文件浏览器是一个...

    VB简单文件浏览器.rar

    一个功能简单的VB文件浏览器雏形,初学者练手做着玩的,还不很完善,只是实现了基本的文件浏览功能,点击浏览按钮可自动显示当前文件下的所有文件,根据用户的操作再显示相应的文件。

    QrpView QRP文件浏览器

    一款用于浏览QRP文件的浏览器,操作方便,解压可以直接运行exe即可

    ES文件浏览器

    安卓下的ES文件浏览器3.1.0.3,可以方便的管理和操作安卓设备上的文件。

    类似文件浏览器的vc++应用程序

    类似于文件浏览器的vc++应用程序,容易使用,能进行各种文件操作.-similar to the File Browser vc applications, easy to use, can perform file operations.

    文件浏览器(含源码)

    上次发的文件浏览器放了放源码了,这次加上源码。 其实现的功能是,利用线程搜索某个文件夹下的所有文件,还可以以精确或模糊搜索文件和文件夹,其工作都是在线程中进行的,不影响当前操作。为了增强实用性,对于...

    文件浏览器

    Android文件浏览器。这是一个自己做的一个文件浏览器,主要是针对sdcard的操作,还有一些控件的使用。用到了AlertDalog的多种使用。

    基于浏览器的资源管理文件管理源代码

    基于浏览器的资源管理文件管理源代码;浏览系统文件、目录,以及对其进行删除、移动等操作的功能

    java跨全域兼容ie/ff/chrome浏览器多文件上传(原创)

    使用jquery/jsp/servlet/iframe实现跨浏览器跨全(子)域多文件上传操作.希望能给大家带来帮助.

    python操作浏览器.zip

    帮助你快速入门浏览器基本操作,用好之后可用来做秒杀工具哦。

Global site tag (gtag.js) - Google Analytics