js二进制

169 阅读9分钟

一、blob(类文件对象)

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

(1)Blob 创建

1.1创建

new Blob(array, options);

array:由 ArrayBufferArrayBufferViewBlobDOMString 等对象构成的,将会被放进 Blob

options:可选的 BlobPropertyBag 字典,它可能会指定如下两个属性

  • type:默认值为 "",表示将会被放入到 blob 中的数组内容的 MIME 类型。
  • endings:默认值为"transparent",用于指定包含行结束符\n的字符串如何被写入,不常用。

1.2示例

const blob = new Blob(["Hello World"], {type: "text/plain"});
console.log(blob.size); // 11
console.log(blob.type); // "text/plain"

(2)Blob 分片

1.1创建

const blob = instanceOfBlob.slice([start [, end [, contentType]]]};

其有三个参数:

  • start:设置切片的起点,即切片开始位置。默认值为 0,这意味着切片应该从第一个字节开始;
  • end:设置切片的结束点,会对该位置之前的数据进行切片。默认值为blob.size
  • contentType:设置新 blob 的 MIME 类型。如果省略 type,则默认为 blob 的原始值。

1.2示例

const iframe = document.getElementsByTagName("iframe")[0];
​
const blob = new Blob(["Hello World"], {type: "text/plain"});
​
const subBlob = blob.slice(0, 5); // Helloiframe.src = URL.createObjectURL(subBlob); 

二、File(blob类型的特殊对象、储存文件)

File 对象是特殊类型的 Blob,且可以用在任意的 Blob 类型的 context 中。Blob 的属性和方法都可以用于 File 对象(File 对象中只存在于浏览器环境中,在 Node.js 环境中不存在。)

1.1特殊属性

  • lastModified:引用文件最后修改日期,为自1970年1月1日0:00以来的毫秒数;
  • lastModifiedDate:引用文件的最后修改日期;
  • name:引用文件的文件名;
  • size:引用文件的文件大小;
  • type:文件的媒体类型(MIME);
  • webkitRelativePath:文件的路径或 URL。

1.2获取方式

  • <input> 元素上选择文件后返回的 FileList 对象;

    <input type="file" id="fileInput" multiple="multiple">
    const fileInput = document.getElementById("fileInput");fileInput.onchange = (e) => {
        console.log(e.target.files);
    }
    
  • 文件拖放

    <div id="drop-zone"></div>
    const dropZone = document.getElementById("drop-zone");dropZone.ondragover = (e) => {
        e.preventDefault();
    }
    ​
    dropZone.ondrop = (e) => {
        e.preventDefault();
        const files = e.dataTransfer.files;
        console.log(files)
    }
    

三、fileReader(读取文件并提取其内容)

FileReader 是一个异步 API,用于读取文件并提取其内容以供进一步使用。

1.1创建

const reader = new FileReader();

1) 属性

  • error:表示在读取文件时发生的错误;
  • result:文件内容。该属性仅在读取操作完成后才有效,数据的格式取决于使用哪个方法来启动读取操作。
  • readyState:表示FileReader状态的数字。 0 : 还没有加载任何数据, 1:数据正在被加载 , 2 : 已完成全部的读取请求。

2)方法

  • readAsArrayBuffer():读取指定 Blob 中的内容,完成之后,result 属性中保存的将是被读取文件的 ArrayBuffer 数据对象;
  • FileReader.readAsBinaryString():读取指定 Blob 中的内容,完成之后,result 属性中将包含所读取文件的原始二进制数据;
  • FileReader.readAsDataURL():读取指定 Blob 中的内容,完成之后,result 属性中将包含一个data: URL 格式的 Base64 字符串以表示所读取文件的内容。
  • FileReader.readAsText():读取指定 Blob 中的内容,完成之后,result 属性中将包含一个字符串以表示所读取的文件内容。

3)事件

  • abort:该事件在读取操作被中断时触发;
  • error:该事件在读取操作发生错误时触发;
  • load:该事件在读取操作完成时触发;
  • progress:该事件在读取 Blob 时触发。

1.2示例

<input type="file" id="fileInput">
const fileInput = document.getElementById("fileInput");
​
const reader = new FileReader();fileInput.onchange = (e) => {
    reader.readAsText(e.target.files[0]);
}
​
reader.onload = (e) => {
    console.log(e.target.result);
}
<input type="file" id="fileInput" />

<img id="preview" />

    const fileInput = document.getElementById("fileInput");
const preview = document.getElementById("preview");
const reader = new FileReader();

fileInput.onchange = (e) => {
  reader.readAsDataURL(e.target.files[0]);
};

reader.onload = (e) => {
  preview.src = e.target.result;
  console.log(e.target.result);
};
const reader = new FileReader();

reader.onprogress = (e) => {
  if (e.loaded && e.total) {
    const percent = (e.loaded / e.total) * 100;
    console.log(`上传进度: ${Math.round(percent)} %`);
  }
});

四、ArrayBuffer(通用的、固定长度的原始二进制数据缓冲区)

ArrayBuffer 对象用来表示通用的、固定长度的原始二进制数据缓冲区。ArrayBuffer 的内容不能直接操作,只能通过 DataView 对象或 ArrayBuffer 对象用来访问

  • TypedArray:用来生成内存的视图,通过9个构造函数,可以生成9种数据格式的视图。
  • DataViews:用来生成内存的视图,可以自定义格式和字节序。

(1)ArrayBuffer

1、new ArrayBuffer()

new ArrayBuffer(bytelength)
  • 参数:它接受一个参数,即 bytelength,表示要创建数组缓冲区的大小(以字节为单位。);
  • 返回值:返回一个新的指定大小的ArrayBuffer对象,内容初始化为0。

2、ArrayBuffer.prototype.byteLength

const buffer = new ArrayBuffer(16); 
console.log(buffer.byteLength);  // 16

只读属性,表示 ArrayBuffer 的 byte 的大小,在 ArrayBuffer 构造完成时生成,不可改变

3、ArrayBuffer.prototype.slice()

const buffer = new ArrayBuffer(16); 
console.log(buffer.slice(0, 8));  // 8

方法可以用来截取 ArrayBuffer 实例,它返回一个新的 ArrayBuffer

4、ArrayBuffer.isView(),

判断参数是否是 TypedArray 实例或者 DataView 实例, typedArray或者DataView的实例为true

const buffer = new ArrayBuffer(16);
ArrayBuffer.isView(buffer)   // false

const view = new DataView(buffer);
ArrayBuffer.isView(view)     // true

(2)typedArray

TypedArray 对象一共提供 9 种类型的视图,每一种视图都是一种构造函数

元素类型化数组字节描述
Int8Int8Array18 位有符号整数
Uint8Uint8Array18 位无符号整数
Uint8CUint8ClampedArray18 位无符号整数
Int16Int16Array216 位有符号整数
Uint16Uint16Array216 位无符号整数
Int32Int32Array432 位有符号整数
Uint32Uint32Array432 位无符号整数
Float32Float32Array432 位浮点
Float64Float64Array864 位浮点

Uint8Array: 将 ArrayBuffer 中的每个字节视为一个整数,可能的值从 0 到 255 (一个字节等于 8 位)。 这样的值称为“8 位无符号整数”。

Uint16Array:将 ArrayBuffer 中任意两个字节视为一个整数,可能的值从 0 到 65535。 这样的值称为“16 位无符号整数”。

Uint32Array: 将 ArrayBuffer 中任何四个字节视为一个整数,可能值从 0 到 4294967295,这样的值称为“32 位无符号整数”

那typedArray格式的数组和数组有什么区别呢?

  • 类型化数组的元素都是连续的,不会为空;
  • 类型化数组的所有成员的类型和格式相同;
  • 类型化数组元素默认值为 0;
  • 类型化数组本质上只是一个视图层,不会存储数据,数据都存储在更底层的 ArrayBuffer 对象中。

1、new TypedArray()

new Int8Array(length);
new Int8Array(typedArray);
new Int8Array(object);
new Int8Array(buffer [, byteOffset [, length]]);
new Int8Array(new Uint8Array(length));
new Int8Array(16);
new Int8Array([1,2,3,4]);
new Int32Array(new ArrayBuffer(8), 4)
new Int8Array(new Int8Array(6));

2、BYTES_PER_ELEMENT

表示这种数据类型占据的字节数:

Int8Array.BYTES_PER_ELEMENT // 1
Uint8Array.BYTES_PER_ELEMENT // 1
Int16Array.BYTES_PER_ELEMENT // 2
Uint16Array.BYTES_PER_ELEMENT // 2
Int32Array.BYTES_PER_ELEMENT // 4
Uint32Array.BYTES_PER_ELEMENT // 4
Float32Array.BYTES_PER_ELEMENT // 4
Float64Array.BYTES_PER_ELEMENT // 8

或者

const buffer = new ArrayBuffer(16); 
const view = new Uint32Array(buffer); 
console.log(view.BYTES_PER_ELEMENT); // 4

3、 TypedArray.prototype.buffer

返回内存中对应的 ArrayBuffer对象,只读属性

const a = new Uint32Array(8);
const b = new Int32Array(a.buffer); 
console.log(a, b);

4、TypedArray.prototype.slice

可以返回一个指定位置的新的 TypedArray实例。

const view = new Int16Array(8);
console.log(view.slice(0 ,5));

5、byteLength 和 length

  • byteLength:返回 TypedArray 占据的内存长度,单位为字节;
  • length:返回 TypedArray 元素个数;
const view = new Int16Array(8);
view.length;      // 8
view.byteLength;  // 16

(3)DataView

DataView 视图是一个可以从 二进制 ArrayBuffer 对象中读写多种数值类型的底层接口

new DataView(buffer [, byteOffset [, byteLength]])
  • buffer:一个已经存在的 ArrayBuffer 对象,DataView 对象的数据源。
  • byteOffset:可选,此 DataView 对象的第一个字节在 buffer 中的字节偏移。如果未指定,则默认从第一个字节开始。
  • byteLength:可选,此 DataView 对象的字节长度。如果未指定,这个视图的长度将匹配 buffer 的长度
const buffer = new ArrayBuffer(16);
const view = new DataView(buffer);
console.log(view);

1、buffer、byteLength、byteOffset

  • buffer:返回对应的ArrayBuffer对象;
  • byteLength:返回占据的内存字节长度;
  • byteOffset:返回当前视图从对应的ArrayBuffer对象的哪个字节开始。
const buffer = new ArrayBuffer(16);
const view = new DataView(buffer);
view.buffer;
view.byteLength;
view.byteOffset;

2、读取数据

DataView 实例提供了以下方法来读取内存,它们的参数都是一个字节序号,表示开始读取的字节位置:

  • getInt8:读取1个字节,返回一个8位整数。
  • getUint8:读取1个字节,返回一个无符号的8位整数。
  • getInt16:读取2个字节,返回一个16位整数。
  • getUint16:读取2个字节,返回一个无符号的16位整数。
  • getInt32:读取4个字节,返回一个32位整数。
  • getUint32:读取4个字节,返回一个无符号的32位整数。
  • getFloat32:读取4个字节,返回一个32位浮点数。
  • getFloat64:读取8个字节,返回一个64位浮点数。
const buffer = new ArrayBuffer(24);
const view = new DataView(buffer);

// 从第1个字节读取一个8位无符号整数
const view1 = view.getUint8(0);

// 从第2个字节读取一个16位无符号整数
const view2 = view.getUint16(1);

// 从第4个字节读取一个16位无符号整数
const view3 = view.getUint16(3);

5、写入内存

setInt8:写入1个字节的8位整数。
setUint8:写入1个字节的8位无符号整数。
setInt16:写入2个字节的16位整数。
setUint16:写入2个字节的16位无符号整数。
setInt32:写入4个字节的32位整数。
setUint32:写入4个字节的32位无符号整数。
setFloat32:写入4个字节的32位浮点数。
setFloat64:写入8个字节的64位浮点数。

五、Object URL

Object URL(MDN定义名称)又称Blob URL(W3C定义名称),是HTML5中的新标准

其实Blob URL/Object URL 是一种伪协议,允许将 Blob 和 File 对象用作图像、二进制数据下载链接等的 URL 源

<input type="file" id="fileInput" />
<img id="preview" />
const fileInput = document.getElementById("fileInput");
const preview = document.getElementById("preview");

fileInput.onchange = (e) => {
  preview.src = URL.createObjectURL(e.target.files[0]);
  console.log(preview.src);
};
  • createObjectURL
  • revokeObjectURL

六、Base64

Base64 是一种基于64个可打印字符来表示二进制数据的表示方法

  • atob():解码,解码一个 Base64 字符串;
  • btoa():编码,从一个字符串或者二进制数据编码一个 Base64 字符串。
atob():解码,解码一个 Base64 字符串;
btoa():编码,从一个字符串或者二进制数据编码一个 Base64 字符串。
btoa("JavaScript")       // 'SmF2YVNjcmlwdA=='
atob('SmF2YVNjcmlwdA==') // 'JavaScript'

七、格式转化

  • ArrayBuffer → blob

const blob = new Blob([new Uint8Array(buffer, byteOffset, length)]);
  • ArrayBuffer → base64

const base64 = btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)));
  • base64 → blob

const base64toBlob = (base64Data, contentType, sliceSize) => {
  const byteCharacters = atob(base64Data);
  const byteArrays = [];

  for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
    const slice = byteCharacters.slice(offset, offset + sliceSize);

    const byteNumbers = new Array(slice.length);
    for (let i = 0; i < slice.length; i++) {
      byteNumbers[i] = slice.charCodeAt(i);
    }

    const byteArray = new Uint8Array(byteNumbers);
    byteArrays.push(byteArray);
  }

  const blob = new Blob(byteArrays, {type: contentType});
  return blob;
}
  • blob → ArrayBuffer

function blobToArrayBuffer(blob) { 
  return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = () => resolve(reader.result);
      reader.onerror = () => reject;
      reader.readAsArrayBuffer(blob);
  });
}
  • blob → base64

function blobToBase64(blob) {
  return new Promise((resolve) => {
    const reader = new FileReader();
    reader.onloadend = () => resolve(reader.result);
    reader.readAsDataURL(blob);
  });
}
  • blob → Object URL

const objectUrl = URL.createObjectURL(blob);