前端数据流处理

前端数据流处理

Posted on 2017-05-26

Blob对象

一个Blob对象就是一个包含有只读原始数据的类文件对象。Blob对象中的数据并不一定得是JavaScript中的原生形式。File接口基于Blob,继承了Blob的功能,并且扩展支持了用户计算机上的本地文件

Blob对象可以看做是存放二进制数据的容器,此外还可以通过Blob设置二进制数据的MIME类型。

创建Blob

var blob = new Blob(dataArray:Array<any>, opt:{type:string});
  • dataArray:数组,包含了要添加到Blob对象中的数据,数据可以是任意多个ArrayBuffer,ArrayBufferView, Blob,或者 DOMString对象。
  • opt:对象,用于设置Blob对象的属性(如:MIME类型)

属性 Blob.size Blob 对象中所包含数据的大小(字节)。 Blob.type 一个字符串,表明该Blob对象所包含数据的MIME类型。如果类型未知,则该值为空字符串

方法

Blob.slice([start,[ end ,[contentType]]])

返回一个新的 Blob对象,包含了源 Blob对象中指定范围内的数据

  • start:开始索引,默认为0
  • end:截取结束索引(不包括end)
  • contentType:新Blob的MIME类型,默认为空字符串

示例

var debug = {hello: "world"};
var blob = new Blob([JSON.stringify(debug, null, 2)],
  {type : 'application/json'});
// 使用 Blob 创建一个指向类型数组的URL

var typedArray = GetTheTypedArraySomehow();
var blob = new Blob([typedArray], {type: "application/octet-binary"});// 传入一个合适的MIME类型
var url = URL.createObjectURL(blob);
// 会产生一个类似blob:d3958f5c-0777-0845-9dcf-2cb28783acaf 这样的URL字符串
// 你可以像使用一个普通URL那样使用它,比如用在img.src上
// 从 Blob 中提取数据
// 从Blob中读取内容的唯一方法是使用 FileReader。以下代码将 Blob 的内容作为类型数组读取:
var reader = new FileReader();
reader.addEventListener("loadend", function() {
   // reader.result 包含转化为类型数组的blob
});
reader.readAsArrayBuffer(blob);

TypedArray

随着Web应用的发展,越来越多地需要使用JavaScript来处理视频、音频,或者通过WebSocks获取原始数据。很显然,我们需要有一种方法能够方便快捷地地用JavaScript处理原始二进制数据。过去,我们将原始数据作为字符串来对待,并使用charCodeAt()来从数据缓冲区中读取字节。由于需要进行多次转换,这种方法低效而且容易出错,特别是当数据格式不是实际上的字节数据时(如32位整数或是浮点数)。

JavaScript的类型化数组(TypedArrays)提供了一个更加高效的机制来访问和处理二进制数据

为了达到最大的灵活性和高效性,JavaScript的TypedArray分为两个部分:缓冲区视图

缓冲区由ArrayBuffer实现,一个缓冲区是一个代表某个数据块的对象。它没有格式,而且没有提供一个机制来访问或操纵其中的内容。为了存取缓冲区中的内容,你需要创建一个视图。视图提供了一个环境(context),包括数据类型、起始偏移量以及元素数量。它把数据转化为实际上的类型化数组。视图由ArrayBufferView和它的一些子类实现。

ArrayBufferView的子类: 下面的子类提供了特定的缓冲区视图,用来处理不同类型的数据。要注意的是,如果要处理的数据类型超过一字节,将使用平台对应的端序。如果需要操作端序,可以使用DataView来代替ArrayBufferView. Int8Array 、Uint8Array、Int16Array、Uint16Array、Int32Array、Uint32Array、Float32Array、Float64Array

ArrayBufferView的父类:

  • DataView:DataView提供了一个底层接口来从ArrayBuffer中存取数据
  • StringView:StringView提供了一个构建于ArrayBuffer之上的C语言风格的字符串操作接口(比如说字符编码的数组,类似JavaScript中的ArrayBufferView)
//创建一个16字节的缓冲区,自动初始化为全0
var buffer = new ArrayBuffer(16);

//检测缓冲区大小
if (buffer.byteLength == 16 ) {
    alert("it's 16 bytes.");
}

//为了能操作这个缓冲区,我们创建一个视图,将缓冲区中的数据看成32位(4字节)有符号整数数组
var int32View = new Int32Array(buffer);

//现在可以像操作一个数组那样操作里面的数据了。下面的这个操作会把数组中的四个元素赋值为0, 2, 4, 6
for (var i = 0; i < int32View.length; i++) {
    int32View[i] = i * 2;
}

// 使用多个视图来操作同一个缓冲区。如果你的机器是小端序(一般都是小端序),将显示[ 0, 0, 2, 0, 4, 0, 6, 0 ]。如果是大端序,显示[0, 0, 0, 2, 0, 4, 0, 6]
var int16View = new Int16Array(buffer);
console.log(int16View)

通过把不同类型、不同起始偏移量的数据组合成单个的缓冲区,我们可以创建和访问类似C语言结构体的数据。

struct someStruct {
    unsigned long id;
    char username[16];
    float amountDue;
};
var buffer = new ArrayBuffer(24);

// Uint16Array(ArrayBuffer buffer, optional unsigned long byteOffset, optional unsigned long length);
//第一个参数是ArrayBuffer,第二个参数是偏移量(以字节计),第三个参数是数据的长度(以字节计)

var idView = new Uint32Array(buffer, 0, 1);
var usernameView = new Uint8Array(buffer, 4, 16);
var amountDueView = new Float32Array(buffer, 20, 1);

在处理完一个类型化的数组之后,有时我们想把它转化为一个普通的数组,因为这样可以使用数组原型提供的方便的方法。

var typedArray = new Uint8Array( [ 1, 2, 3, 4 ] ),
    normalArray = Array.apply( [], typedArray );
normalArray.length === 4;
normalArray.constructor === Array;

ArrayBuffer

ArrayBuffer (缓冲数组)是一种用于呈现通用、固定长度的二进制数据的类型,不能直接构造并填充 ArrayBuffer 的内容,你可以创建一个类型化的数组对象typed array objects或一个DataView对象,它以特定的格式表示缓冲区,并使用它读取和写入缓冲区的内容。

构造函数 ArrayBuffer ArrayBuffer(unsigned long length);

属性 ArrayBuffer.length: ArrayBuffer构造函数的length属性

方法 ArrayBuffer.isView(arg): 如果参数是ArrayBuffer的视图实例就返回true,例如 typed array objects 或 DataView。否则返回false

ArrayBuffer.transfer(oldBuffer [, newByteLength]): 返回一个新的ArrayBuffer,其内容取自oldBuffer的数据,并且根据 newByteLength 的大小来对数据进行截取或者以0扩展。

示例

// 创建了一个8字节的缓冲区,并使用一个Int32Array 进行呈现:
var buffer = new ArrayBuffer(8);
var view   = new Int32Array(buffer);

DataView

可使用 DataView 对象在 ArrayBuffer 中的任何位置读取和写入不同类型的二进制数据

new DataView(buffer [, byteOffset [, byteLength]])
  • buffer 一个现有的ArrayBuffer,用 作DataView 实例的存储空间.
  • byteOffset 可选 视图实例引用的buffer的字节偏移量.如果没有指定,buffer视图会以首字节作为开始。
  • byteLength 可选 字节数组中元素的个数。如果未指定,视图的长度将会以buffer的长度匹配

方法

getInt8: 在相对于视图开始处的指定字节偏移量位置处获取 Int8 
setInt8: 在相对于视图开始处的指定字节偏移量位置处存储 Int8 值。

getFloat32: 在相对于视图开始处的指定字节偏移量位置处获取 Float32 值。
setFloat32: 在相对于视图开始处的指定字节偏移量位置处存储 Float32 值。

示例

// 使用 DataView 对象处理从 XmlHttpRequest 获取的二进制数据:
var req = new XMLHttpRequest();
    req.open('GET', "http://www.example.com");
    req.responseType = "arraybuffer";
    req.send();

    req.onreadystatechange = function () {
        if (req.readyState === 4) {
            var buffer = req.response;
            var dataView = new DataView(buffer);
            var ints = new Int32Array(dataView.byteLength / 4);
            for (var i = 0; i < ints.length; i++) {
                ints[i] = dataview.getInt32(i * 4);
            }
        alert(ints[10]);
        }
    }

File

文件(File) 接口提供有关文件的信息,并允许网页中的 JavaScript 访问其内容。

通常情况下, File 对象是来自用户在一个<input> 元素上选择文件后返回的 FileList 对象,也可以是来自由拖放操作生成的 DataTransfer 对象,或者来自 HTMLCanvasElement 上的 mozGetAsFile() API

File 对象是特殊类型的 Blob,且可以用在任意的 Blob 类型的 context 中。比如说, FileReader, URL.createObjectURL(), createImageBitmap(), 及 XMLHttpRequest.send() 都能处理 Blob 和 File

属性 File.lastModified 只读 返回当前 File 对象所引用文件最后修改时间, 自 1970年1月1日0:00 以来的毫秒数。 File.lastModifiedDate 只读 返回当前 File 对象所引用文件最后修改时间的 Date 对象。 File.name 只读 返回当前 File 对象所引用文件的名字。 File.size 只读 返回文件的大小。 File.webkitRelativePath 只读 返回 File 相关的 path 或 URL。 File.type 只读 返回文件的 多用途互联网邮件扩展类型

方法 File 接口没有定义任何方法,但是继承了 Blob 接口的方法

FileReader

FileReader 对象允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据。 File对象不包含文件的数据

其中 File 对象可以是来自用户在一个<input>元素上选择文件后返回的FileList对象, 也可以来自拖放操作生成的 DataTransfer对象,还可以是来自在一个HTMLCanvasElement上执行mozGetAsFile()方法后返回结果.

let reader = new FileReader();

状态值

EMPTY	0	还没有加载任何数据.
LOADING	1	数据正在被加载.
DONE	2	已完成全部的读取请求.

属性

error: DOMError	 = 在读取文件时发生的错误. 只读.
readyState: unsigned short = 表明FileReader对象的当前状态. 值为State constants中的一个. 只读
result: jsval= 读取到的文件内容.这个属性只在读取操作完成之后才有效,并且数据的格式取决于读取操作是由哪个方法发起的. 只读.

方法

// 中止该读取操作.在返回时,readyState属性的值为DONE.
void abort(); 

// 开始读取指定的Blob对象或File对象中的内容. 当读取操作完成时,readyState属性的值会成为DONE,如果设置了onloadend事件处理程序,则调用之.同时,result属性中将包含一个ArrayBuffer对象以表示所读取文件的内容. blob参数为将要读取的Blob对象或者File对象.
void readAsArrayBuffer(in Blob blob);

// 开始读取指定的Blob对象或File对象中的内容. 当读取操作完成时,readyState属性的值会成为DONE,如果设置了onloadend事件处理程序,则调用之.同时,result属性中将包含所读取文件的原始二进制数据. blob参数为将要读取的Blob对象或者File对象.
void readAsBinaryString(in Blob blob);

// 开始读取指定的Blob对象或File对象中的内容. 当读取操作完成时,readyState属性的值会成为DONE,如果设置了onloadend事件处理程序,则调用之.同时,result属性中将包含一个data: URL格式的字符串以表示所读取文件的内容. blob参数为将要读取的Blob对象或者File对象.
void readAsDataURL(in Blob blob);

// 开始读取指定的Blob对象或File对象中的内容. 当读取操作完成时,readyState属性的值会成为DONE,如果设置了onloadend事件处理程序,则调用之.同时,result属性中将包含一个字符串以表示所读取的文件内容.
void readAsText(in Blob blob, [optional] in DOMString encoding);

事件处理

onabort: 当读取操作被中止时调用.
onerror: 当读取操作发生错误时调用.
onload: 当读取操作成功完成时调用.
onloadend: 当读取操作完成时调用,不管是成功还是失败.该处理程序在onload或者onerror之后调用.
onloadstart: 当读取操作将要开始之前调用.
onprogress: 在读取数据过程中周期性调用.

示例

<!doctype html>
<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />

<script type="text/javascript">
oFReader = new FileReader(), rFilter = /^(?:image\/bmp|image\/cis\-cod|image\/gif|image\/ief|image\/jpeg|image\/jpeg|image\/jpeg|image\/pipeg|image\/png|image\/svg\+xml|image\/tiff|image\/x\-cmu\-raster|image\/x\-cmx|image\/x\-icon|image\/x\-portable\-anymap|image\/x\-portable\-bitmap|image\/x\-portable\-graymap|image\/x\-portable\-pixmap|image\/x\-rgb|image\/x\-xbitmap|image\/x\-xpixmap|image\/x\-xwindowdump)$/i;

oFReader.onload = function (oFREvent) {
  document.getElementById("uploadPreview").src = oFREvent.target.result;
};

function loadImageFile() {
  if (document.getElementById("uploadImage").files.length === 0) { return; }
  var oFile = document.getElementById("uploadImage").files[0];
  if (!rFilter.test(oFile.type)) { alert("You must select a valid image file!"); return; }
  oFReader.readAsDataURL(oFile);
}
</script>
</head>

<body onload="loadImageFile();">
  <form name="uploadForm">
    <img id="uploadPreview" style="width: 100px; height: 100px;" alt="Image preview" />
    <input id="uploadImage" type="file" name="myPhoto" onchange="loadImageFile();" />
  </form>
</body>
</html>

DataTransfer

TextEncoder, TextDecoder

数据的编解码

var uint8array = new TextEncoder("utf-8").encode("¢");
var string = new TextDecoder("utf-8").decode(uint8array);

Image

// 创建一个Image对象
var a=new Image();    
// 定义Image对象的src, 就相当于给浏览器缓存了一张图片
a.src="xxx.gif"
创建Image对象: new Image([width],[height])

Image对象属性: border complete height hspace lowsrc name src vspace width

Image对象的事件:onabort onerror onkeydown onkeypress onkeyup onload

需要注意的是:src 属性一定要写到 onload 的后面,否则程序在 IE 中会出错。

可以通过Image对象的complete 属性来检测图像是否加载完成(每个Image对象都有一个complete属性,当图像处于加载中时,该属性值false,当发生了onload、onerror、onabort中任何一个事件后,则表示图像装载过程结束(不管成没成功),此时complete属性为true)

var img = new Image();
var div = document.getElementById('foo');

img.onload = function() {
  div.appendChild(img);
};

img.src = 'path/to/image.jpg';