美文网首页
JS二进制文件等数据的操作

JS二进制文件等数据的操作

作者: 漫舞莲华倾人醉 | 来源:发表于2021-12-16 19:15 被阅读0次

    二进制数组

    概念介绍

    ArrayBuffer对象、TypedArray视图和DataView视图是 JavaScript 操作二进制数据的一个接口。它们都是以数组的语法处理二进制数据,所以统称为二进制数组。

    二进制数组由三类对象组成。

    (1)ArrayBuffer对象:代表内存之中的一段二进制数据,可以通过“视图”进行操作。“视图”部署了数组接口,这意味着,可以用数组的方法操作内存。

    (2)TypedArray视图:共包括 9 种类型的视图,比如Uint8Array(无符号 8 位整数)数组视图, Int16Array(16 位整数)数组视图, Float32Array(32 位浮点数)数组视图等等。

    (3)DataView视图:可以自定义复合格式的视图,比如第一个字节是 Uint8(无符号 8 位整数)、第二、三个字节是 Int16(16 位整数)、第四个字节开始是 Float32(32 位浮点数)等等,此外还可以自定义字节序。

    • 简单说,ArrayBuffer对象代表原始的二进制数据,TypedArray视图用来读写简单类型的二进制数据,DataView视图用来读写复杂类型的二进制数据

    一、ArrayBuffer 对象

    1. 概念介绍

    • ArrayBuffer对象代表储存二进制数据的一段内存,它不能直接读写,只能通过视图(TypedArray视图和- - DataView视图)来读写,视图的作用是以指定格式解读二进制数据。

    • 通俗点的话就是arrbuffer是一个数组,只不过这个数组有点特殊,你只能看不能改,但是可以通过“视图”进行操作

    2. 对象使用

    ArrayBuffer也是一个构造函数,可以分配一段可以存放数据的连续内存区域。

    const buf = new ArrayBuffer(32);
    

    上面代码生成了一段 32 字节的内存区域,每个字节的值默认都是 0。可以看到,ArrayBuffer构造函数的参数是所需要的内存大小(单位字节)。

    3. 实例属性和方法

    ArrayBuffer 对象有实例属性 byteLength ,表示当前实例占用的内存字节长度(单位字节),一旦创建就不可变更(只读)

    const buffer = new ArrayBuffer(32); 其中32表示二进制数据占用的字节长度。
    buffer.byteLength; // 32
    

    ArrayBuffer 对象有实例方法 slice(),用来复制一部分内存。

    参数如下:

    • start,整数类型,表示开始复制的位置。默认从 0 开始。
    • end,整数类型,表示结束复制的位置(不包括结束的位置)。如果省略,则表示复制到结束。
    const buffer = new ArrayBuffer(32);
    const buffer2 = buffer.slice(0);
    

    二、DataView 视图

    1. 概念介绍

    因为ArrayBuffer只能读,不能写,所以为了可以编辑数据,DataView 视图和TypedArray出现了,DataView 视图是一个可以从二进制ArrayBuffer对象中读写多种数值类型的底层接口,使用它时,不用考虑不同平台的字节序问题,主要用来读写复杂类型的二进制数据**。

    2. 对象使用

    const buf = new ArrayBuffer(32);
    

    为了读写这段内容,需要为它指定视图。DataView视图的创建,需要提供ArrayBuffer对象实例作为参数。

    const buf = new ArrayBuffer(32);
    const dataView = new DataView(buf);
    dataView.getUint8(0) // 0
    

    上面代码对一段 32 字节的内存,建立DataView视图,然后以不带符号的 8 位整数格式,从头读取 8 位二进制数据,结果得到 0,因为原始内存的ArrayBuffer对象,默认所有位都是 0。

    三、TypedArray 视图

    1. 概念介绍

    • 一个类型化数组(TypedArray)对象描述了一个底层的二进制数据缓冲区(binary data buffer)的一个类数组视图(view).
    • 因为ArrayBuffer只能读不能写,没啥用。但是借助于TypedArray或者DataView就可以修改ArrayBuffer的内容
    • 你可以把TypedArray想象成一个基类,其中Uint8Array、Float32Array等都继承于TypedArray(实际并不是继承!)

    2. 对象使用

    TypedArray视图,与DataView视图的一个区别是,它不是一个构造函数,而是一组构造函数,代表不同的数据格式。

    const buffer = new ArrayBuffer(12);
    
    const x1 = new Int32Array(buffer);
    x1[0] = 1;
    const x2 = new Uint8Array(buffer);
    x2[0]  = 2;
    
    x1[0] // 2
    
    • 上面代码对同一段内存,分别建立两种视图:32 位带符号整数(Int32Array构造函数)和 8 位不带符号整数(Uint8Array构造函数)。由于两个视图对应的是同一段内存,一个视图修改底层内存,会影响到另一个视图。

    • TypedArray视图的构造函数,除了接受ArrayBuffer实例作为参数,还可以接受普通数组作为参数,直接分配内存生成底层的ArrayBuffer实例,并同时完成对这段内存的赋值。

    const typedArray = new Uint8Array([0,1,2]);
    typedArray.length // 3
    
    typedArray[0] = 5;
    typedArray // [5, 1, 2]
    
    • 上面代码使用TypedArray视图的Uint8Array构造函数,新建一个不带符号的 8 位整数视图。可以看到,Uint8Array直接使用普通数组作为参数,对底层内存的赋值同时完成。

    3. 不同类型的一组构造函数

    • 解释其中一种,其他的类似:
      Uint8Array 数组类型表示一个8位无符号整型数组,创建时内容被初始化为0,里面的每个元素只占一个字节。创建完后,可以以对象的方式或使用数组下标索引的方式引用数组中的元素。
    • TypedArray视图支持的数据类型一共有 9 种(DataView视图支持除Uint8C以外的其他 8 种)。
    数据类型 字节长度 含义 对应的 C 语言类型
    Int8 1 8 位带符号整数 signed char
    Uint8 1 8 位不带符号整数 unsigned char
    Uint8C 1 8 位不带符号整数(自动过滤溢出) unsigned char
    Int16 2 16 位带符号整数 short
    Uint16 2 16 位不带符号整数 unsigned short
    Int32 4 32 位带符号整数 int
    Uint32 4 32 位不带符号的整数 unsigned int
    Float32 4 32 位浮点数 float
    Float64 8 64 位浮点数 double

    4. 操作实例

    • 实例主要实现了前端使用TypedArray编辑二进制
      因为ArrayBuffer只读不可写,所以先把ArrayBuffer转换为可以编辑的TypedArray, 然后修改typedArray的内容, 接着再把二进制的数据转化为blob类型的数据,再把blob对象转化为一个url数据, 接着就可以把blob文件下载下来:
        var ab = new ArrayBuffer(32)
        var iA = new Int8Array(ab)
        iA[0] = 97;//把二进制的数据的首位改为97 ,97为小写字母a的ascll码;
        var blob = new Blob([iA], {type: "application/octet-binary"});//把二进制的码转化为blob类型
        var url = URL.createObjectURL(blob);
        window.open(url)
    

    Blob

    一、概念介绍

    • Blob 对象表示一个不可变、原始数据的类文件对象。它的数据可以按文本或二进制的格式进行读取,也可以转换成 ReadableStream 来用于数据操作。

    • Blob 表示的不一定是JavaScript原生格式的数据。File 接口基于Blob,继承了 blob 的功能并将其扩展使其支持用户系统上的文件。

    • 在实际Web应用中,Blob更多是图片二进制形式的上传与下载,虽然其可以实现几乎任意文件的二进制传输。

    二、创建对象

    • 创建Blob对象的方法有几种,可以调用Blob构造函数,还可以使用一个已有Blob对象上的slice()方法切出另一个Blob对象,还可以调用canvas对象上的toBlob方法。

    三、属性

    Blob对象有两个属性,参见下表:

    属性名 类型 描述
    size unsigned long long(表示可以很大的数值) Blob对象中所包含数据的大小。字节为单位。 只读。
    type DOMString 一个字符串,表明该Blob对象所包含数据的MIME类型。例如,上demo图片MIME类似就是”image/jpeg“. 如果类型未知,则该值为空字符串。 只读。

    四、构造函数

    构造函数
    与FormData对象类似,Blob也有一个构造函数用法。语法如下:

    Blob Blob(
      [可选] Array parts,
      [可选] BlobPropertyBag properties
    );
    

    例如:

    var myBlob= new Blob(arrayBuffer);
    

    其中,两个参数的含义是:

    • parts

      一个数组,包含了将要添加到Blob对象中的数据。数组元素可以是任意多个的ArrayBuffer, ArrayBufferView(typed array), Blob, 或者DOMString对象。

    • properties

      一个对象,设置Blob对象的一些属性。目前仅支持一个type属性,表示Blob的类型。

    五、方法

    Blob对象有个很重要的方法-slice(),作用是,可以实现文件的分割!

    具体使用方法如下,和数组slice相似:

    Blob slice(
      [可选] long long start,
      [可选] long long end,
      [可选] DOMString contentType
    };
    

    参数释义:

    • start

      开始索引,可以为负数,语法类似于数组的slice方法。默认值为0.

    • end

      结束索引,可以为负数,语法类似于数组的slice方法。默认值为最后一个索引。

    • contentType

      • 新的Blob对象的MIME类型,这个值将会成为新的Blob对象的type属性的值,默认为一个空字符串。
        • 显然,此方法返回的数据格式还是Blob对象,不过是指定范围复制的新的Blob对象。注意,如果start参数的值比源Blob对象的size属性值还大,则返回的Blob对象的size值为0,也就是不包含任何数据。

    四、举例

    Blob获取图片并二进制显示demo

    var eleAppend = document.getElementById("forAppend");
    window.URL = window.URL || window.webkitURL;
    if (typeof history.pushState == "function") {
        var xhr = new XMLHttpRequest();    
        xhr.open("get", "/image/study/s/s256/mm1.jpg", true);
        xhr.responseType = "blob";
        xhr.onload = function() {
            if (this.status == 200) {
                var blob = this.response;
                var img = document.createElement("img");
                img.onload = function(e) {
                  window.URL.revokeObjectURL(img.src); // 清除释放
                };
                img.src = window.URL.createObjectURL(blob);
                eleAppend.appendChild(img);    
            }
        }
        xhr.send();
    } else {
        eleAppend.innerHTML = '<p style="color:#cd0000;">浏览器不给力,还是早点回去给孩子喂奶吧~</p>';    
    }
    

    Arraybuffer和Blob的区别

    • ArrayBuffer其实就是一块连续内存,所以是low-level的。你可以将这块内存映射为某种数组(TypedArray)或者是自定义的数据视图(DataView),将来如果JS有了Struct(或TypedObject),有可能可以映射为结构体(Struct)或结构体数组。

    • Blob则是一个相对high-level的概念,来自于数据库,可以认为就是「文件」(所以blob是有文件类型的,即mime type),只不过是脱离具体文件系统的文件(不需要有文件名、文件路径之类的东西)。

    • Blob对象并不对应内存,一个blob引用更像文件句柄,你读取blob的内容,可以是全放进一个ArrayBuffer里,也可以直接得到一个字符串(如果是文本文件),还可以通过Stream来读取,特别是blob很大的情况下内存也放不下,只能通过流处理。

    • 注意,Blob并不像ArrayBuffer是JS语言内置的,而是Web API,Node.js的API里就没有Blob。这也是为什么MDN说Blob表示的不一定是JavaScript原生格式的数据。

    • Blob 用于操作二进制文件 ArrayBuffer 用于操作内存

    • 大白话来说就是ArrayBuffer表达的是一片可编辑的内存,很类似于Node里的Buffer或者其它语言里动态分配的内存。里面的数据是可读可写的。而Blob表示的是一个做为一个整体的二进制文件,更多的目的是直接使用它

    ArrayBuffer和TypedArray,以及Blob的使用

    1. 前端使用TypedArray编辑二进制

    var ab = new ArrayBuffer(32)
    var iA = new Int8Array(ab)
    iA[0] = 97;//把二进制的数据的首位改为97 ,97为小写字母a的ascll码;
    var blob = new Blob([iA], {type: "application/octet-binary"});//把二进制的码转化为blob类型
    var url = URL.createObjectURL(blob);
    window.open(url)
    

    2. FileReader读区blob文件

    var ab = new ArrayBuffer(32)
    var iA = new Int8Array(ab)
    iA[0] = 97
    var blob = new Blob([iA], {type: "application/octet-binary"});
    var fr = new FileReader();
    fr.addEventListener("load", function(ev) {
        console.log(ev.target.result);//会输出字符:a
    });
    fr.readAsText(blob)
    

    3. blob转化为typedArray

    var ab = new ArrayBuffer(32)
    var iA = new Int8Array(ab)
    iA[0] = 97
    var blob = new Blob([iA], {type: "application/octet-binary"});
    var fr = new FileReader();
    fr.addEventListener("load", function(ev) {
        var abb = ev.target.result;
        var iAA = new Int8Array(abb);
        console.log(iAA);
    });
    //把blob文件转化为arraybuffer;
    fr.readAsArrayBuffer(blob)
    
    • arraybuffer -->> typedarray -->> blob -->> blob通过FileReader转化为 arraybuffer或者text文本或者base64字符串;

    • arraybuffer和typedarray主要是处理二进制, 如果要把blob往二进制转换, 必须先把blob转换为arraybuffer, 然后再转换为可以编辑的typedArray;

    • 实际上, 还有一种比较常用的数据类型, base64编码的数据, 常用的比如image的base64的编码, 文本的base64编码等, 也可以把base64的编码转化为对应的ascll码,再转化为typearray ,然后再生成blob对象:

    4. base64的编码生成blob

    function dataURLtoBlob(dataurl) {
        var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
        bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
        //通过atob把base64转化为ascll码, 然后再把ascll码转化为字节码
        while(n--){
          u8arr[n] = bstr.charCodeAt(n);
        }
      //u8arr就是2进制的数据
      return new Blob([u8arr], {type:mime});
    } 
    

    相关文章

      网友评论

          本文标题:JS二进制文件等数据的操作

          本文链接:https://www.haomeiwen.com/subject/kmwvfrtx.html