`
yiminghe
  • 浏览: 1460246 次
  • 性别: 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  
看了之后除了惊讶就是佩服,不知道博主的学习方法是什么,如何能够从一个问题到寻找答案的?

相关推荐

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

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

    delphi编写的文件浏览器

    在创建文件浏览器时,可以使用TForm作为主窗口,TTreeView或TListView来展示文件系统结构,TOpenDialog和TSaveDialog则可用于打开和保存文件操作。 2. **文件系统访问**:Delphi通过System.IOUtils单元提供对文件...

    android文件系统浏览器

    同时,`java.nio.file.Files`类提供了更强大的文件操作接口,如异步读写、文件属性查询等。 在设计用户界面时,通常会采用RecyclerView或者ListView来显示文件列表,结合Adapter来动态加载数据。每个文件或目录项...

    Ghost 浏览器 ghost 文件浏览器

    4. **分区操作**:除了文件级别的操作,Ghost浏览器还支持对.GHO文件内的分区进行操作。例如,可以将一个分区从映像中分离出来,或者合并到另一个分区中。 5. **安全备份**:通过Ghost浏览器,用户可以对.GHO文件...

    C# 自定义文件浏览器

    【C# 自定义文件浏览器】是一种在.Net框架下构建的扩展功能,用于克服原生文件选择控件的局限性。通常,.Net自带的文件选择对话框(OpenFileDialog或SaveFileDialog)不允许用户选择正在被系统或其他进程占用的文件...

    android 仿ES文件浏览器源码.rar

    Android的文件操作主要通过`java.io`和`java.nio`包实现,源码会涵盖读取、写入、创建、删除、重命名等基本操作。同时,源码可能还使用了`ContentResolver`来与系统的多媒体库交互,获取和管理设备上的图片、视频、...

    本示例实现SD卡文件浏览器

    例如,使用`FileOutputStream`和`FileInputStream`进行文件复制,或者使用`Files.copy()`方法进行更简洁的文件操作。 在实现文件浏览器时,还需考虑错误处理和用户反馈。当文件操作失败时,应提供清晰的错误提示,...

    C#本地文件浏览器

    在信息技术领域,文件浏览器是一个不可或缺的工具,它允许用户方便地浏览、管理和操作计算机上的文件和目录。本项目“C#本地文件浏览器”旨在提供一个简洁而实用的界面,让用户能够高效地进行本地文件系统的探索。...

    OPERA9.1浏览器绿色单文件版,可在PE下使用的浏览器

    **OPERA9.1浏览器绿色单文件版** Opera 9.1是一款经典的网络浏览器,以其高效、稳定和功能丰富而闻名。"绿色单文件版"指的是这个版本的Opera浏览器是便携式的,无需安装即可使用,且所有配置信息和数据都存储在同一...

    网络浏览器管理文件

    总的来说,`phpFileManager`作为一款网络浏览器管理文件的工具,它体现了Web技术在文件管理领域的应用,使得远程服务器的文件操作变得更加便捷和高效。尽管现在可能有更多先进的解决方案,但了解这样的历史背景可以...

    Qt文件浏览器,Linux

    8. 菜单栏和工具栏:提供常用的文件操作功能,如新建、打开、保存、打印等。 开发过程中,开发者可能会使用到的QT库和模块包括但不限于: - QtWidgets:提供基本的GUI元素,如按钮、标签、文本框等。 - QtCore:...

    文件浏览器

    在文件浏览器的代码中,常见的功能模块包括文件树视图的生成、文件操作接口、搜索功能的实现、权限控制以及错误处理等。这些模块通过良好的设计模式,如MVC(模型-视图-控制器)或MVVM(模型-视图-视图模型)进行...

    Re安卓文件浏览器

    它支持常见的文件操作,如复制、剪切、粘贴、重命名、删除以及创建新文件夹,使得用户能够方便快捷地整理自己的文件系统。此外,该应用还具有搜索功能,可迅速定位到所需文件,节省了用户的时间。 特别值得一提的是...

    树目录文件浏览器_C#_文件浏览器_

    5. **文件操作**:文件浏览器还可能包括读取、复制、移动和删除文件的选项。这涉及到File和FileInfo类,以及相关的文件操作方法,如Copy、Move和Delete。 6. **事件驱动编程**:在Windows Forms应用中,用户交互...

    SD开文件浏览器

    5. **文件操作**:在文件浏览器中,用户可以进行的基本文件操作包括: - **浏览**:查看文件和文件夹的列表。 - **打开**:启动与文件关联的应用来查看或编辑内容。 - **创建**:新建文件或文件夹。 - **编辑**...

    基于QT的文件浏览器.zip

    【基于QT的文件浏览器】是一种使用QT开发框架构建的应用程序,它允许用户浏览和操作本地文件系统。...这个过程中,不仅可以学习到GUI编程,还能深入理解操作系统级别的文件操作,提升软件开发能力。

    Qt-C++实现文件浏览器

    在本文中,我们将深入探讨如何使用Qt-C++框架来实现一个功能完备的文件浏览器。Qt是一个跨平台的应用程序开发框架,支持多种操作系统,包括Windows、Linux、macOS等。使用Qt,我们可以方便地构建GUI(图形用户界面)...

    VB 小巧的文件浏览器

    【VB小巧的文件浏览器】是一款...通过分析和实践这样的项目,VB初学者可以深入理解文件操作、控件使用、事件驱动编程以及面向对象编程的思想。此外,还能锻炼到GUI设计和交互逻辑的实现,有助于提升整体的编程技能。

Global site tag (gtag.js) - Google Analytics