热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

HTML5读取本地文件

本文转自:转:http:hushicai.com20140329html5-du-qu-ben-di-wen-jian.html感谢大神分享。常见的语言比如php、shell等,是如何

本文转自:转:http://hushicai.com/2014/03/29/html5-du-qu-ben-di-wen-jian.html感谢大神分享。

常见的语言比如php、shell等,是如何读取文件的呢?

实际上,大多数语言都需要先获取文件句柄,然后调用文件访问接口,打开文件句柄,读取文件!

那么,HTML5是否也是这样的呢?

答案是肯定的!

HTML5为我们提供了一种与本地文件系统交互的标准方式:File Api。

该规范主要定义了以下数据结构:

  • File
  • FileList
  • Blob

HTML5访问本地文件系统时,需要先获取File对象句柄,怎么获取文件引用句柄呢?

选择文件

首先检测一下当前浏览器是否支持File Api

function isSupportFileApi() {
    if(window.File && window.FileList && window.FileReader && window.Blob) {
        return true;
    }
    return false;
}

HTML5虽然可以让我们访问本地文件系统,但是js只能被动地读取,也就是说只有用户主动触发了文件读取行为,js才能访问到File Api,这通常发生在表单选择文件或者拖拽文件

表单输入

表单提交文件是最常见的场景,用户选择文件后,触发了文件选择框的change事件,通过访问文件选择框元素的files属性可以拿到选定的文件列表。

如果文件选择框指定了multiple,则一个文件选择框可以同时选择多个文件,files包含了所有选择的文件对象;如果没有指定,则只能选择一个文件,files[0]就是所选择的文件对象。

function fileSelect1(e) {
    var files = this.files;
    for(var i = 0, len = files.length; i ) {
        var f = files[i];
        html.push(
            '

', f.name + '(' + (f.type || "n/a") + ')' + ' - ' + f.size + 'bytes', '

' ); } document.getElementById('list1').innerHTML = html.join(''); } document.getElementById('file1').Onchange= fileSelect1;

拖拽

拖拽是另一种常见的文件访问场景,这种方式通过一个叫dataTransfer的接口来获得拖拽的文件列表,更多关于dataTransfer。

拖拽同样支持多选,用户可以拖拽多个文件。

function dropHandler(e) {
    e.stopPropagation();
    e.preventDefault();

    var files = e.dataTransfer.files;
    for(var i = 0, len = files.length; i ) {
        var f = files[i];
        html.push(
            '

', f.name + '(' + (f.type || "n/a") + ')' + ' - ' + f.size + 'bytes', '

' ); } document.getElementById('list2').innerHTML = html.join(''); } function dragOverHandler(e) { e.stopPropagation(); e.preventDefault(); e.dataTransfer.dragEffect = 'copy'; } var drag = document.getElementById('drag'); drag.addEventListener('drop', dropHandler, false); drag.addEventListener('dragover', dragOverHandler, false);

PS:
拖拽有个特别需要注意的事情就是,阻止事件冒泡和事件默认行为,防止浏览器自动打开文件等行为,比如拖拽一个pdf,浏览器可能会打开pdf。

至此,我们知道,我们可以通过两种方式来获得文件句柄,那么如何读取文件内容呢?

读取文件

HTML5提供了一个叫FileReader的接口,用于异步读取文件内容,它主要定义了以下几个方法:

  • readAsBinaryString(File|Blob)
  • readAsText(File|Blob [, encoding])
  • readAsDataURL(File|Blob)
  • readAsArrayBuffer(File|Blob)

FileReader还提供以下事件:

  • onloadstart
  • onprogress
  • onload
  • onabort
  • onerror
  • onloadend

一旦调用了以上某个方法读取文件后,我们可以监听以上任何一个事件来获得进度、结果等。

预览本地图片

这里主要用到FileReader的readAsDataURL方法,通过将图片数据读取成Data URI的方法,将图片展示出来。

function fileSelect2(e) {
    e = e || window.event;
    var files = this.files;
    var p = document.getElementById('preview2');

    for(var i = 0, f; f = files[i]; i++) {
        var reader = new FileReader();
        reader.onload = (function(file) {
            return function(e) {
                var span = document.createElement('span');
                span.innerHTML = ''+ file.name +'';

                p.insertBefore(span, null);
            };
        })(f);
        //读取文件内容
        reader.readAsDataURL(f);
    }
}
document.getElementById('files2').addEventListener('change', fileSelect2, false);

调用FileReader的readAsDataURL接口时,浏览器将异步读取文件内容,通过给FileReader实例监听一个onload事件,数据加载完毕后,在onload事件处理中,通过reader的result属性即可获得文件内容。

预览文本文件

这里主要用到FileReader的readAsText,对于诸如mimeType为text/plain、text/html等文件均认为是文本文件,即mineType为text开头都可以用这个方法来预览。

function fileSelect3(e) {
    e = e || window.event;

    var files = this.files;
    var p = document.getElementById('preview3');

    for(var i = 0, f; f = files[i]; i++) {
        var reader = new FileReader();
        reader.onload = (function(file) {
            return function(e) {
                var div = document.createElement('div');
                div.className = "text"
                div.innerHTML = encodeHTML(this.result);

                p.insertBefore(div, null);
            };
        })(f);
        //读取文件内容
        reader.readAsText(f);
    }
}
document.getElementById('files3').addEventListener('change', fileSelect3, false);

PS:由于需要在页面上预览文本,所以则需要对文件中的html特殊字符进行实体编码,避免浏览器解析文件中的html代码。

监控读取进度

既然FileReader是异步读取文件内容,那么就应该可以监听它的读取进度。

事实上,FileReader的onloadstart以及onprogress等事件,可以用来监听FileReader的读取进度。

在onprogress的事件处理器中,有一个ProgressEvent对象,这个事件对象实际上继承了Event对象,提供了三个只读属性:

  • lengthComputable
  • loaded
  • total

通过以上几个属性,即可实时显示读取进度,不过需要注意的是,此处的进度条是针对单次读取的进度,即一次readAsBinaryString等方法的读取进度。

var input4 = document.getElementById('file4');
var bar = document.getElementById('progress-bar');
var progress = document.getElementById('progress');
function startHandler(e) {
    bar.style.display = 'block';
}
function progressHandler(e) {
    var percentLoaded = Math.round((e.loaded / e.total) * 100);
    if (percentLoaded <100) {
        progress.style.width = percentLoaded + '%';
        progress.textContent = percentLoaded + '%';
    }
}
function loadHandler(e) {
    progress.textContent = '100%';
    progress.style.width = '100%';
}
function fileSelect4(e) {
    var file = this.files[0];
    if(!file) {
        alert('请选择文件!');
        return false;
    }
    if(file.size > 500 * 1024 * 1024) {
        alert('文件太大,请选择500M以下文件,防止浏览器崩溃!');
        return false;
    }
    progress.style.width = '0%';
    progress.textContent = '0%';
    var reader = new FileReader();
    reader.onloadstart = startHandler;
    reader.onprogress = progressHandler;
    reader.onload = loadHandler;
    reader.readAsBinaryString(this.files[0]);
}
input4.onchange = fileSelect4;

分割文件

有的时候,一次性将一个大文件读入内存,并不是一个很好的选择(如果文件太大,可能直接导致浏览器崩溃),上述的监听进度示例就有可能在文件太大的情况下崩溃。

更稳健的方法是分段读取!

分段读取文件

HTML5 File Api提供了一个slice方法,允许分片读取文件内容。

function readBlob(start, end) {
    var files = document.getElementById('file5').files;

    if(!files.length) {
        alert('请选择文件');
        return false;
    }

    var file = files[0],
        start = parseInt(start, 10) || 0,
        end = parseInt(end, 10) || (file.size - 1);

    var r = document.getElementById('range'),
        c = document.getElementById('content');

    var reader = new FileReader();
    reader.onloadend = function(e) {
        if(this.readyState == FileReader.DONE) {
            c.textContent = this.result;
            r.textContent = "Read bytes: " + (start + 1) + " - " + (end + 1) + " of " + file.size + " bytes";
        }
    };

    var blob;
    if(file.webkitSlice) {
        blob = file.webkitSlice(start, end + 1);
    } else if(file.mozSlice) {
        blob = file.mozSlice(start, end + 1);
    } else if(file.slice) {
        blob = file.slice(start, end + 1);
    }

    reader.readAsBinaryString(blob);
};
document.getElementById('file5').Onchange= function() {
    readBlob(10, 100);
}

本例使用了FileReader的onloadend事件来检测读取成功与否,如果用onloadend则必须检测一下FileReader的readyState,因为read abort时也会触发onloadend事件,如果我们采用onload,则可以不用检测readyState。

分段读取进度

那分段读取一个大文件时,如何监控整个文件的读取进度呢?

这种情况下,因为我们调用了多次FileReader的文件读取方法,跟上文一次性把一个文件读到内存中的情况不大相同,不能用onprogress来监控。

我们可以监听onload事件,每次onload代表每个片段读取完毕,我们只需要在onload中计算已读取的百分比就可以了!

var bar2 = document.getElementById('progress-bar2');
var progress2 = document.getElementById('progress2');
var input6 = document.getElementById('file6');
var block = 1 * 1024 * 1024; // 每次读取1M
// 当前文件对象
var file;
// 当前已读取大小
var fileLoaded;
// 文件总大小
var fileSize;

// 每次读取一个block
function readBlob2() {
    var blob;
    if(file.webkitSlice) {
        blob = file.webkitSlice(fileLoaded, fileLoaded + block + 1);
    } else if(file.mozSlice) {
        blob = file.mozSlice(fileLoaded, fileLoaded + block + 1);
    } else if(file.slice) {
        blob = file.slice(fileLoaded, fileLoaded + block + 1);
    } else {
        alert('不支持分段读取!');
        return false;
    }
    reader.readAsBinaryString(blob);
}
// 每个blob读取完毕时调用
function loadHandler2(e) {
   fileLoaded += e.total;
   var percent = fileLoaded / fileSize;
   if(percent <1)  {
       // 继续读取下一块
       readBlob2();
   } else {
       // 结束
       percent = 1;
   }
   percent = Math.ceil(percent * 100) + '%';
   progress2.innerHTML = percent;
   progress2.style.width = percent;
}
function fileSelect6(e) {
    file = this.files[0];
    if(!file) {
        alert('文件不能为空!');
        return false;
    }
    fileLoaded = 0;
    fileSize = file.size;
    bar2.style.display = 'block';
    // 开始读取
    readBlob2();
}
var reader = new FileReader();
// 只需监听onload事件
reader.Onload= loadHandler2;
input6.onchange = fileSelect6

注意事项

在chrome浏览器上测试时,如果直接以file://xxx这种形式访问demo,会出现FileReader读取不到内容的情况,表现为FileReader的result为空或者FileReader根本就没有去读取文件内容,FileReader各个事件没有触发;

这种情况我想应该是类似于chrome不允许添加本地COOKIE那样,chrome也不允许以file://xxx这种页面上的js代码访问文件内容;

解决办法很简单,只需要将测试文件放到一个web服务器上,以http://xxx形式访问即可。

参考文章

  • http://www.html5rocks.com/en/tutorials/file/dndfiles/

转:http://hushicai.com/2014/03/29/html5-du-qu-ben-di-wen-jian.html


推荐阅读
  • 在分析和解决 Keepalived VIP 漂移故障的过程中,我们发现主备节点配置如下:主节点 IP 为 172.16.30.31,备份节点 IP 为 172.16.30.32,虚拟 IP 为 172.16.30.10。故障表现为监控系统显示 Keepalived 主节点状态异常,导致 VIP 漂移到备份节点。通过详细检查配置文件和日志,我们发现主节点上的 Keepalived 进程未能正常运行,最终通过优化配置和重启服务解决了该问题。此外,我们还增加了健康检查机制,以提高系统的稳定性和可靠性。 ... [详细]
  • 本文将继续探讨 JavaScript 函数式编程的高级技巧及其实际应用。通过一个具体的寻路算法示例,我们将深入分析如何利用函数式编程的思想解决复杂问题。示例中,节点之间的连线代表路径,连线上的数字表示两点间的距离。我们将详细讲解如何通过递归和高阶函数等技术实现高效的寻路算法。 ... [详细]
  • 技术分享:使用 Flask、AngularJS 和 Jinja2 构建高效前后端交互系统
    技术分享:使用 Flask、AngularJS 和 Jinja2 构建高效前后端交互系统 ... [详细]
  • 为了确保iOS应用能够安全地访问网站数据,本文介绍了如何在Nginx服务器上轻松配置CertBot以实现SSL证书的自动化管理。通过这一过程,可以确保应用始终使用HTTPS协议,从而提升数据传输的安全性和可靠性。文章详细阐述了配置步骤和常见问题的解决方法,帮助读者快速上手并成功部署SSL证书。 ... [详细]
  • Python 伦理黑客技术:深入探讨后门攻击(第三部分)
    在《Python 伦理黑客技术:深入探讨后门攻击(第三部分)》中,作者详细分析了后门攻击中的Socket问题。由于TCP协议基于流,难以确定消息批次的结束点,这给后门攻击的实现带来了挑战。为了解决这一问题,文章提出了一系列有效的技术方案,包括使用特定的分隔符和长度前缀,以确保数据包的准确传输和解析。这些方法不仅提高了攻击的隐蔽性和可靠性,还为安全研究人员提供了宝贵的参考。 ... [详细]
  • C++ 异步编程中获取线程执行结果的方法与技巧及其在前端开发中的应用探讨
    本文探讨了C++异步编程中获取线程执行结果的方法与技巧,并深入分析了这些技术在前端开发中的应用。通过对比不同的异步编程模型,本文详细介绍了如何高效地处理多线程任务,确保程序的稳定性和性能。同时,文章还结合实际案例,展示了这些方法在前端异步编程中的具体实现和优化策略。 ... [详细]
  • POJ 2482 星空中的星星:利用线段树与扫描线算法解决
    在《POJ 2482 星空中的星星》问题中,通过运用线段树和扫描线算法,可以高效地解决星星在窗口内的计数问题。该方法不仅能够快速处理大规模数据,还能确保时间复杂度的最优性,适用于各种复杂的星空模拟场景。 ... [详细]
  • JavaScript XML操作实用工具类:XmlUtilsJS技巧与应用 ... [详细]
  • PTArchiver工作原理详解与应用分析
    PTArchiver工作原理及其应用分析本文详细解析了PTArchiver的工作机制,探讨了其在数据归档和管理中的应用。PTArchiver通过高效的压缩算法和灵活的存储策略,实现了对大规模数据的高效管理和长期保存。文章还介绍了其在企业级数据备份、历史数据迁移等场景中的实际应用案例,为用户提供了实用的操作建议和技术支持。 ... [详细]
  • 在最近的项目中,我们广泛使用了Qt框架的网络库,过程中遇到了一些挑战和问题。本文旨在记录这些经验和解决方案,以便日后参考。鉴于我们的客户端GUI完全基于Qt开发,我们期望利用其强大的网络功能进行Fiddler网络数据包的捕获与分析,以提升开发效率和应用性能。 ... [详细]
  • 在对WordPress Duplicator插件0.4.4版本的安全评估中,发现其存在跨站脚本(XSS)攻击漏洞。此漏洞可能被利用进行恶意操作,建议用户及时更新至最新版本以确保系统安全。测试方法仅限于安全研究和教学目的,使用时需自行承担风险。漏洞编号:HTB23162。 ... [详细]
  • 在配置Nginx的SSL证书后,虽然HTTPS访问能够正常工作,但HTTP请求却会遇到400错误。本文详细解析了这一问题,并提供了Nginx配置的具体示例。此外,还深入探讨了DNS服务器证书、SSL证书的申请与安装流程,以及域名注册、查询方法和CDN加速技术的应用,帮助读者全面了解相关技术细节。 ... [详细]
  • 本指南介绍了如何在ASP.NET Web应用程序中利用C#和JavaScript实现基于指纹识别的登录系统。通过集成指纹识别技术,用户无需输入传统的登录ID即可完成身份验证,从而提升用户体验和安全性。我们将详细探讨如何配置和部署这一功能,确保系统的稳定性和可靠性。 ... [详细]
  • Vue应用预渲染技术详解与实践 ... [详细]
  • 并发编程入门:初探多任务处理技术
    并发编程入门:探索多任务处理技术并发编程是指在单个处理器上高效地管理多个任务的执行过程。其核心在于通过合理分配和协调任务,提高系统的整体性能。主要应用场景包括:1) 将复杂任务分解为多个子任务,并分配给不同的线程,实现并行处理;2) 通过同步机制确保线程间协调一致,避免资源竞争和数据不一致问题。此外,理解并发编程还涉及锁机制、线程池和异步编程等关键技术。 ... [详细]
author-avatar
我的明天谁2502931447
这个家伙很懒,什么也没留下!
Tags | 热门标签
RankList | 热门文章
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有