又是阮一峰:文件和二进制数据的操作 - 从来没这么佩服一个没见过面的人

文件和二进制数据的操作 

来自《JavaScript 标准参考教程(alpha)》,by 阮一峰

目录

历史上,JavaScript无法处理二进制数据。如果一定要处理的话,只能使用charCodeAt()方法,一个个字节地从文字编码转成二进制数据,还有一种办法是将二进制数据转成Base64编码,再进行处理。这两种方法不仅速度慢,而且容易出错。ECMAScript 5引入了Blob对象,允许直接操作二进制数据。

Blob对象是一个代表二进制数据的基本对象,在它的基础上,又衍生出一系列相关的API,用来操作文件。

  • File对象:负责处理那些以文件形式存在的二进制数据,也就是操作本地文件;
  • FileList对象:File对象的网页表单接口;
  • FileReader对象:负责将二进制数据读入内存内容;
  • URL对象:用于对二进制数据生成URL。

Blob对象

Blob(Binary Large Object)对象代表了一段二进制数据,提供了一系列操作接口。其他操作二进制数据的API(比如File对象),都是建立在Blob对象基础上的,继承了它的属性和方法。

生成Blob对象有两种方法:一种是使用Blob构造函数,另一种是对现有的Blob对象使用slice方法切出一部分。

(1)Blob构造函数,接受两个参数。第一个参数是一个包含实际数据的数组,第二个参数是数据的类型,这两个参数都不是必需的。

var htmlParts = ["<a id=\"a\"><b id=\"b\">hey!<\/b><\/a>"];

var myBlob = new Blob(htmlParts, { "type" : "text\/xml" });

下面是一个利用Blob对象,生成可下载文件的例子。

var blob = new Blob(["Hello World"]);

var a = document.createElement("a");
a.href = window.URL.createObjectURL(blob);
a.download = "hello-world.txt";
a.textContent = "Download Hello World!";

body.appendChild(a);

上面的代码生成了一个超级链接,点击后提示下载文本文件hello-world.txt,文件内容为“Hello World”。

(2)Blob对象的slice方法,将二进制数据按照字节分块,返回一个新的Blob对象。

var newBlob = oldBlob.slice(startingByte, endindByte);

下面是一个使用XMLHttpRequest对象,将大文件分割上传的例子。

function upload(blobOrFile) {
  var xhr = new XMLHttpRequest();
  xhr.open('POST', '/server', true);
  xhr.onload = function(e) { ... };
  xhr.send(blobOrFile);
}

document.querySelector('input[type="file"]').addEventListener('change', function(e) {
  var blob = this.files[0];

  const BYTES_PER_CHUNK = 1024 * 1024; // 1MB chunk sizes.
  const SIZE = blob.size;

  var start = 0;
  var end = BYTES_PER_CHUNK;

  while(start < SIZE) {
    upload(blob.slice(start, end));

    start = end;
    end = start + BYTES_PER_CHUNK;
  }
}, false);

})();

(3)Blob对象有两个只读属性:

  • size:二进制数据的大小,单位为字节。
  • type:二进制数据的MIME类型,全部为小写,如果类型未知,则该值为空字符串。

在Ajax操作中,如果xhr.responseType设为blob,接收的就是二进制数据。

FileList对象

FileList对象针对表单的file控件。当用户通过file控件选取文件后,这个控件的files属性值就是FileList对象。它在结构上类似于数组,包含用户选取的多个文件。

<input type="file" id="input" onchange="console.log(this.files.length)" multiple />

当用户选取文件后,就可以读取该文件。

var selected_file = document.getElementById('input').files[0];

采用拖放方式,也可以得到FileList对象。

var dropZone = document.getElementById('drop_zone');
dropZone.addEventListener('drop', handleFileSelect, false);

function handleFileSelect(evt) {
    evt.stopPropagation();
    evt.preventDefault();

    var files = evt.dataTransfer.files; // FileList object.

    // ...
}

上面代码的 handleFileSelect 是拖放事件的回调函数,它的参数evt是一个事件对象,该参数的dataTransfer.files属性就是一个FileList对象,里面包含了拖放的文件。

File对象

File对象是FileList对象的成员,包含了文件的一些元信息,比如文件名、上次改动时间、文件大小和文件类型。它的属性值如下:

  • name:文件名,该属性只读。
  • size:文件大小,单位为字节,该属性只读。
  • type:文件的MIME类型,如果分辨不出类型,则为空字符串,该属性只读。
  • lastModifiedDate:文件的上次修改时间。

var selected_file = document.getElementById('input').files[0];

var fileName = selected_file.name;
var fileSize = selected_file.size;
var fileType = selected_file.type;

FileReader对象

FileReader对象用于读取文件,即把文件内容读入内存。它的参数是File对象或Blob对象。

对于不同类型的文件,FileReader使用不同的方法读取。

  • readAsBinaryString(Blob|File):返回二进制字符串,该字符串每个字节包含一个0到255之间的整数。
  • readAsText(Blob|File, opt_encoding) :返回文本字符串。默认情况下,文本编码格式是'UTF-8',可以通过可选的格式参数,指定其他编码格式的文本。
  • readAsDataURL(Blob|File):返回一个基于Base64编码的data-uri对象。
  • readAsArrayBuffer(Blob|File) :返回一个ArrayBuffer对象。

readAsText方法用于读取文本文件,它的第一个参数是File或Blob对象,第二个参数是前一个参数的编码方法,如果省略就默认为UTF-8编码。该方法是异步方法,一般监听onload事件,用来确定文件是否加载结束,方法是判断FileReader实例的result属性是否有值。其他三种读取方法,用法与readAsText方法类似。

var reader = new FileReader();

reader.onload = function(e) {
  var text = reader.result;
}

reader.readAsText(file, encoding);

readAsDataURL方法返回一个data URL,它的作用基本上是将文件数据进行Base64编码。你可以将返回值设为图像的src属性。

var reader = new FileReader();

reader.onload = function(e) {
  var dataURL = reader.result;
}

reader.readAsDataURL(file);

readAsBinaryString方法可以读取任意类型的文件,而不仅仅是文本文件,返回文件的原始的二进制内容。这个方法与XMLHttpRequest.sendAsBinary方法结合使用,就可以使用JavaScript上传任意文件到服务器。

var reader = new FileReader();

reader.onload = function(e) {
  var rawData = reader.result;
}

reader.readAsBinaryString(file);

readAsArrayBuffer方法读取文件,返回一个类型化数组(ArrayBuffer),即固定长度的二进制缓存数据。在文件操作时(比如将JPEG图像转为PNG图像),这个方法非常方便。

var reader = new FileReader();

reader.onload = function(e) {
  var arrayBuffer = reader.result;
}

reader.readAsArrayBuffer(file);

除了以上四种不同的读取文件方法,FileReader对象还有一个abort方法,用于中止文件上传。

var reader = new FileReader();

reader.abort();

FileReader对象采用异步方式读取文件,可以为一系列事件指定回调函数。

  • onabort方法:读取中断或调用reader.abort()方法时触发。
  • onerror方法:读取出错时触发。
  • onload方法:读取成功后触发。
  • onloadend方法:读取完成后触发,不管是否成功。触发顺序排在 onload 或 onerror 后面。
  • onloadstart方法:读取将要开始时触发。
  • onprogress方法:读取过程中周期性触发。

下面的代码是如何展示文本文件的内容。

var reader = new FileReader();

reader.onload = function(e){
  console.log(e.target.result);
}

reader.readAsText(blob);

onload事件的回调函数接受一个事件对象,该对象的target.result就是文件的内容。

下面是一个使用readAsDataURL方法,为img元素添加src属性的例子。

var reader = new FileReader();

reader.onload = function(e) {
    document.createElement('img').src = e.target.result;

};

reader.readAsDataURL(f);

下面是一个onerror事件回调函数的例子。

var reader = new FileReader();
reader.onerror = errorHandler;

function errorHandler(evt) {
  switch(evt.target.error.code) {
    case evt.target.error.NOT_FOUND_ERR:
      alert('File Not Found!');
      break;
    case evt.target.error.NOT_READABLE_ERR:
      alert('File is not readable');
      break;
    case evt.target.error.ABORT_ERR:
      break;
    default:
      alert('An error occurred reading this file.');
  };
}

下面是一个onprogress事件回调函数的例子,主要用来显示读取进度。

var reader = new FileReader();
reader.onprogress = updateProgress;

function updateProgress(evt) {
  if (evt.lengthComputable) {
    var percentLoaded = Math.round((evt.loaded / evt.totalEric Bidelman) * 100);

    var progress = document.querySelector('.percent');
    if (percentLoaded < 100) {
      progress.style.width = percentLoaded + '%';
      progress.textContent = percentLoaded + '%';
    }
  }
}

读取大文件的时候,可以利用Blob对象的slice方法,将大文件分成小段,逐一读取,这样可以加快处理速度。

综合实例:显示用户选取的本地图片

假设有一个表单,用于用户选取图片。

<input type="file" name="picture" accept="image/png, image/jpeg"/>

一旦用户选中图片,将其显示在canvas的函数可以这样写:

document.querySelector('input[name=picture]').onchange = function(e){
     readFile(e.target.files[0]);
}

function readFile(file){

  var reader = new FileReader();

  reader.onload = function(e){
    applyDataUrlToCanvas( reader.result );
  };

  reader.reaAsDataURL(file);
}

还可以在canvas上面定义拖放事件,允许用户直接拖放图片到上面。

// stop FireFox from replacing the whole page with the file.
canvas.ondragover = function () { return false; };

// Add drop handler
canvas.ondrop = function (e) {
  e.stopPropagation();
  e.preventDefault();
  e = e || window.event;
  var files = e.dataTransfer.files;
  if(files){
    readFile(files[0]);
  }
};

所有的拖放事件都有一个dataTransfer属性,它包含拖放过程涉及的二进制数据。

还可以让canvas显示剪贴板中的图片。

document.onpaste = function(e){
  e.preventDefault();
  if(e.clipboardData&&e.clipboardData.items){
    // pasted image
    for(var i=0, items = e.clipboardData.items;i<items.length;i++){
      if( items[i].kind==='file' && items[i].type.match(/^image/) ){
        readFile(items[i].getAsFile());
        break;
      }
    }
  }
  return false;
};

URL对象

URL对象用于生成指向File对象或Blob对象的URL。

var objecturl =  window.URL.createObjectURL(blob);

上面的代码会对二进制数据生成一个URL,类似于“blob:http%3A//test.com/666e6730-f45c-47c1-8012-ccc706f17191”。这个URL可以放置于任何通常可以放置URL的地方,比如img标签的src属性。需要注意的是,即使是同样的二进制数据,每调用一次URL.createObjectURL方法,就会得到一个不一样的URL。

这个URL的存在时间,等同于网页的存在时间,一旦网页刷新或卸载,这个URL就失效。除此之外,也可以手动调用URL.revokeObjectURL方法,使URL失效。

window.URL.revokeObjectURL(objectURL);

下面是一个利用URL对象,在网页插入图片的例子。

var img = document.createElement("img");

img.src = window.URL.createObjectURL(files[0]);

img.height = 60;

img.onload = function(e) {
    window.URL.revokeObjectURL(this.src);
}

body.appendChild(img);

var info = document.createElement("span");

info.innerHTML = files[i].name + ": " + files[i].size + " bytes";

body.appendChild(info);

还有一个本机视频预览的例子。

var video = document.getElementById('video');
var obj_url = window.URL.createObjectURL(blob);
video.src = obj_url;
video.play()
window.URL.revokeObjectURL(obj_url);

参考链接

时间: 2024-09-08 09:42:45

又是阮一峰:文件和二进制数据的操作 - 从来没这么佩服一个没见过面的人的相关文章

xml-Android Xml文件中二进制数据怎么解析

问题描述 Android Xml文件中二进制数据怎么解析 二进制数据,base-64 解决方案 Android - 读取XML文件中的数据Android数据存储---Pull解析Xml文件将二进制数据放在XML文件中. 解决方案二: 读取那个二级制数据的节点 然后用base64 解密类库 解密 就可以吧

c++-C++下如何从读取文件内的数据并且排序然后输出到另外一个文件

问题描述 C++下如何从读取文件内的数据并且排序然后输出到另外一个文件 如题 大一新手 自学太累了 希望有引路人 拜托各位了 谢谢! 解决方案 即便你学会了,写起来也要好多行,建议你用C#吧.实现整个需求只要1行代码就行了: File.WriteAllLines("输出文件.txt", File.ReadAllLines("文件名.txt").OrderBy(x => 排序条件)); 解决方案二: 自学太累?是你没有用心吧.偶也是自学走过来的,非计算机及相关专

SQL 2005对xml文件与xml数据的操作

由于数据库对xml数据直接处理有很多优势,05也对这方面加强了功能. 但这方面资料少,所以自己做了一些总结,希望会给大家带来帮助 --charry0110(晓风残月) --用SQL多条可以将多条数据组成一棵XML树L一次插入 --将XML树作为varchar参数传入用 --insert xx select xxx from openxml() 的语法插入数据 -----------------------------------导入,导出xml--------------------------

新人求解答—Jquery怎么得到从ashx文件传过来的Json字符串里面的二进制数据!!

问题描述 新人求解答-Jquery怎么得到从ashx文件传过来的Json字符串里面的二进制数据!! 解决方案 <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.4.2.min.js"></script> <script> $.ajax({ url: 'xxxxx.ashx', dataType: 'json', success: function (json) { console.

详解XMLHttpRequest(二)响应属性、二进制数据、监测上传下载进度_javascript技巧

分析并操作 responseXML属性  如果你使用 XMLHttpRequest 来获得一个远程的 XML 文档的内容,responseXML 属性将会是一个由 XML 文档解析而来的 DOM 对象,这很难被操作和分析.这里有五种主要的分析 XML 文档的方式:  1.使用 XPath 定位到文档的制定部分.  2.使用 JXON 将其转换成 JavaScript 对象树.  3.手工的 解析和序列化 XML 为字符串或对象.  4.使用 XMLSerializer 把 DOM 树序列化成字符

在ASP.NET 2.0中操作数据之五十五:编辑和删除现有的二进制数据_自学过程

导言: 在前面的3章里我们为处理二进制数据添加了很多的功能.我们首先在表Categories里添加BrochurePath列,并更新了体系结构.同样,为了处理表Categorie里现有的Picture列,我们在数据访问层和业务逻辑层里增加了相应的方法.同时我们创建一个页面,在GridView控件里显示二进制数据--包含一个指向说明小册子的下载链接,并将每个类的图片显示在<img>元素里.同时我们添加一个DetailsView控件,供用户添加新的类,并上传其图片和小册子数据. 剩下的就是添加编辑

在.jsp文件里面,通过jquery load方法加载另一个.jsp文件,请问这2个.jsp文件是否共享数据呢?

问题描述 1.问题里面的共享数据是指,在.jsp里的脚本代码 定义的变量/对象等举例,<%Cart cart = request.getAttribute("cart");--%>2.再打个比方----包含文件,有2种方法:1).jsp指令<jsp:include page="XXX.jsp"/> //这样包含进来的.jsp文件不共享数据,因为2个.jsp文件 各自独立!2).jsp标准动作<%@ include file="

用VB将WORD文档(或其他的二进制数据)生成xml文件并互相转换

word|xml|二进制|生成xml|数据|转换 用vb将word文档(或其他的二进制数据)生成xml文件并互相转换1.    建立一个新的vb工程2.    引用 Microsoft XML,版本 2.0 或以上3.    在窗体form1上建立按钮 cmdCreateXML 和 cmdGetBinary 代码:Option ExplicitDim oDoc As DOMDocumentDim DOCINPATH As StringDim XMLOUTPATH As StringDim DOC

【C/C++学院】0826-文件重定向/键盘输入流/屏幕输出流/字符串输入输出/文件读写简单操作/字符文件读写二进制与文本差别/get与getline挖掘数据/二进制与文本差别/随机位置/多线程初级

文件重定向 #include<iostream> using namespace std; void main() { char str[30] = { 0 }; cin >> str; cout << str; system(str); cerr << "error for you"; cin.get(); cin.get(); } 键盘输入流 #include<iostream> #include <stdlib.h