js Blob、ArrayBuffer(Uint8Array、TypedArray、DataView)、Buffer、DataUrl

js Blob、ArrayBuffer(Uint8Array、TypedArray、DataView)、Buffer、DataUrl_第1张图片

Blob:
是浏览器环境上提供的一种大对象,通常是影像、声音或多媒体文件等原始数据的二进制对象,它和 ArrayBuffer 没有必然联系,但是又可以互相转化,Blob用于操作二进制文件,而 ArrayBuffer 用于操作内存。
详见Blob

const blob = new Blob( array, options );
  • 第一个参数 array 是一个由ArrayBuffer, ArrayBufferView, Blob, DOMString 等对象构成的 Array ,或者其他类似对象的混合体,它将会被放进 Blob。DOMStrings会被编码为UTF-8。

js Blob、ArrayBuffer(Uint8Array、TypedArray、DataView)、Buffer、DataUrl_第2张图片

var htmlFragment = ['hey!'];
var myBlob = new Blob(htmlFragment, {type : 'text/html'});

  • BlobURL(ObjectURL)是一种伪协议,只能由浏览器在内部生成,我们知道script/img/video/iframe等标签的src属性和background的url可以通过url和base64来显示,我们同样可以把blob或者file转换为url生成BlobURL来展示图像,BlobURL允许Blob和File对象用作图像,下载二进制数据链接等的URL源
    • BlobURL并不代表数据本身,数据存储在浏览器中,BlobUrl只是访问它的key。数据会一直有效,直到关闭浏览器或者手动清除。 因此即使将BlobUrl传递给服务器等也无法访问数据
var droptarget = document.getElementById('droptarget');

droptarget.ondrop = function (e) {
  var files = e.dataTransfer.files;
  for (var i = 0; i < files.length; i++) {
  
    var type = files[i].type;
    if (type.substring(0,6) !== 'image/')
      continue;
    var img = document.createElement('img');
    
    img.src = URL.createObjectURL(files[i]);
    
    img.onload = function () {
      this.width = 100;
      document.body.appendChild(this);
      URL.revokeObjectURL(this.src);
    }
  }
}

  • 下载文件
<body>
 <button onclick="download()">download.txt</button>

 <script>
      const getObjectURL = (file) => {
        let url;
        if (window.createObjectURL) {
          url = window.createObjectURL(file);
        } else if (window.URL) {
          url = window.URL.createObjectURL(file);
        } else if (window.webkitURL) {
          url = window.webkitURL.createObjectURL(file);
        }
        return url;
      };
      function download() {
        const fileName = 'download.txt';
        const myBlob = new Blob(['johnYu'], { type: 'text/plain' });
        downloadFun(fileName, myBlob);
      }
      function downloadFun(fileName, blob) {
        const link = document.createElement('a');
        link.href = getObjectURL(blob);
        link.download = fileName;
        link.click();
        link.remove();
        URL.revokeObjectURL(link.href);
      }
    </script>
  </body>

  • 文件选择器返回一个 FileList 对象,该对象是一个类似数组的成员,每个成员都是一个 File 实例对象。File 实例对象是一个特殊的 Blob 实例,增加了name和lastModifiedDate属性
// HTML 代码如下
// 

function fileinfo(files) {
  for (var i = 0; i < files.length; i++) {
    var f = files[i];
    console.log(
      f.name, // 文件名,不含路径
      f.size, // 文件大小,Blob 实例属性
      f.type, // 文件类型,Blob 实例属性
      f.lastModifiedDate // 文件的最后修改时间
    );
  }
}

  • 服务器返回二进制数据
function getBlob(url, callback) {
  var xhr = new XMLHttpRequest();
  xhr.open('GET', url);
  xhr.responseType = 'blob';
  xhr.onload = function () {
    callback(xhr.response);
  }
  xhr.send(null);
}

  • 生成 URL
var droptarget = document.getElementById('droptarget');

droptarget.ondrop = function (e) {
  var files = e.dataTransfer.files;
  for (var i = 0; i < files.length; i++) {
    var type = files[i].type;
    if (type.substring(0,6) !== 'image/')
      continue;
    var img = document.createElement('img');
    
    img.src = URL.createObjectURL(files[i]);
    
    img.onload = function () {
      this.width = 100;
      document.body.appendChild(this);
      URL.revokeObjectURL(this.src);
    }
  }
}

  • 分片上传
<!-- html部分 -->
<input type="file" id='f' />
<!-- js部分 -->
<script>
function upload(blob) {
    var xhr = new XMLHttpRequest();
    xhr.open('POST', '/ajax', true);
    xhr.setRequestHeader('Content-Type', 'text/plain')
    xhr.send(blob);
}

document.getElementById('f').addEventListener('change', function (e) {
    var blob = this.files[0];
    const CHUNK_SIZE = 20; .
    const SIZE = blob.size;
    var start = 0;
    var end = CHUNK_SIZE;
    while (start < SIZE) {
        upload(blob.slice(start, end));
        start = end;
        end = start + CHUNK_SIZE;
    }
}, false);
</script>
  • FileReader操作Blob对象
var fileReader = new FileReader();

fileReader.readAsText(blob):返回文本,需要指定文本编码,默认为 UTF-8。
fileReader.readAsArrayBuffer(blob):返回 ArrayBuffer 对象。
fileReader.readAsDataURL(blob):返回 Data URL。
fileReader.readAsBinaryString(blob):返回原始的二进制字符串。

DataUrl:
允许内容的创建者将较小的文件嵌入到文档中。由于可以将其用作URL的替代,因此DataURL和BlobUrl一样可以在script/img/video/iframe等标签的src属性和background的url中使用,用法与BlobUrl基本一致

data:[][;base64],data
	data:前缀
	mediatype表明数据类型,是一个MIME类型字符串,如image/jpeg表示一个JPEG图片文件。如果省略,默认值为text/plain;charset=US-ASCII。
	base64:标志位(如果是文本,则可选)
	data:数据本身

js Blob、ArrayBuffer(Uint8Array、TypedArray、DataView)、Buffer、DataUrl_第3张图片
atob(): 负责解码已经使用base64编码了的字符串。
btoa(): 将字符串转为base64编码的ASCII字符串。

btoa('foo') // "PHhtbD5mb288L3htbD4="
atob('PHhtbD5mb288L3htbD4=') // "foo"

  • 文件下载
  <script>
    const createDownload = (fileName, content) => {
      const blob = new Blob([content]);
      const reader = new FileReader();
      const link = document.createElement('a');
      link.innerHTML = fileName;
      link.download = fileName;
      reader.onload = () => {
        link.href = reader.result;
        document.getElementsByTagName('body')[0].appendChild(link);
      };
      reader.readAsDataURL(blob);
    };

    createDownload('download.txt', 'johnYu');
  </script>

  • 与BlobURL的区别
    • DataUrl是直接编码的数据本身。关闭浏览器后仍然可以在地址栏访问,DataUrl由于数据本身由URL表示,因此可以将其保存在Cookie中传递给服务器

    • BlobUrl的长度一般比较短,但DataUrl因为直接存储图片base64编码后的数据,往往很长(Base64编码的数据体积通常会比二进制格式的图片体积大1/3。),因此当显式大图片时,使用BlobUrl能获取更好的可能性,速度和内存比DataUrl更有效

    • DataUrl不会被浏览器缓存,但是小部分会通过css缓存,如避免了让图片独自产生一次HTTP请求,不会每次使用时都加载一次

    • BlobUrl始终是唯一字符串,即时你每次传递相同的Blob,每次也会生成不同的BlobUrl;DataUrl值跟随blob变化;

ArrayBuffer:
是最基础的二进制对象,是对固定长度的连续内存空间的引用,存了一堆字节,也无法直接操作它。
js Blob、ArrayBuffer(Uint8Array、TypedArray、DataView)、Buffer、DataUrl_第4张图片

//创建一个长度为8的ArrayBuffer,此时开辟一个固定8个字节的缓冲区也就是64位
var buffer = new ArrayBuffer(8);

//返回大小
buffer.byteLength	//8

//复制一部分内存,slice用法和js相似
var buf2 = buf1.slice(0);	

如果我们想操作这段内存空间怎么办呢?这时候就需要一个称之为视图的家伙

  • Uint8Array,Uint16Array,Uint32Array等这几个东西就是视图。你可以把它理解成 ArrayBuffer 的翻译器,只不过他们的翻译方式有点不同:

    • Uint8Array 将 ArrayBuffer 中的8位,及每个字节视为一个单位。每个单位是 0 到 255 之间的数字。之所以是255,是因为每个单位最多是 8 位,即 2^8 次方。
    • Uint16Array 将 ArrayBuffer 中的16位,及每 2 个字节视为一个单位,即2^16。每个单位是 0 到 65535 之间的整数。原理同上。
    • Uint32Array 将 ArrayBuffer 中的32位,及每 4 个字节视为一个单位,即2^32。每个单位是 0 到 4294967295 之间的整数。原理同上。
// 我们可以通过 BYTES_PER_ELEMENT 静态属性来得之视图单位的大小
const buf8 = new Uint8Array();
const buf16 = new Uint16Array();
const buf32 = new Uint32Array();
console.log(buf8.BYTES_PER_ELEMENT); // 1
console.log(buf16.BYTES_PER_ELEMENT); // 2
console.log(buf32.BYTES_PER_ELEMENT); // 4

  • TypedArray就是上面提到的 Uint8Array 等的统称。他们都是 TypedArray (类型数组)的一种形式罢了,并不存在 TypedArray 这个构造函数。这只是一个统称
  • 每个位首代表正负符号。故而 Int8Array 每个元素大小范围为-128~127。
    js Blob、ArrayBuffer(Uint8Array、TypedArray、DataView)、Buffer、DataUrl_第5张图片
    js Blob、ArrayBuffer(Uint8Array、TypedArray、DataView)、Buffer、DataUrl_第6张图片
    js Blob、ArrayBuffer(Uint8Array、TypedArray、DataView)、Buffer、DataUrl_第7张图片
    js Blob、ArrayBuffer(Uint8Array、TypedArray、DataView)、Buffer、DataUrl_第8张图片
  • 换算为10进制,Uint16Array中每个元素大小范围为 0 ~ 2^16 也就是 0 ~ 65536 。
// 创建8个字节长度的缓存冲
const buffer = new ArrayBuffer(8);

const uint8Array = new Uint8Array(buffer);

// log: [0, 0, 0, 0,0, 0, 0, 0]
console.log(uint8Array);

// 将buffer转化为Uint16Array
// Uint8Array中每一个元素表示两个字节(16位)
const uint16Array = new Uint16Array(buffer);

// log: Uint16Array(4) [ 0, 0, 0, 0 ]
console.log(uint16Array);

// 64位 8字节 -> 4个元素(log:4)
console.log(uint16Array.length);
//



  • DataView是一种底层的,更灵活的读取 ArrayBuffer 的视图。 从上文中我们知道诸如 Unit8Array 之类的 “翻译器” (视图)可以用来翻译 ArrayBuffer,但有的时候我们并不想固化 “翻译” 类型,比如我有的时候想用 8 翻译,有的时候想用 16 翻译。DataView 就是一种更灵活的视图,相较与 TypedArray 每个元素中固定的字节大小,我们可以通过 DataView 来自由的操作 ArrayBuffer
new DataView(buffer [, byteOffset [, byteLength]])
  • 第一个参数 buffer 为必填,它支持传入一个 ArrayBuffer 表示 DataView 中的源数据。
  • 第二个参数 byteOffset 选填,它表示创建 DataView 时开头从 buffer 的哪个字节开始,可以作为启始偏移量。未指定时,默认从第一个字节开始。
  • 第三个参数 btyeLength 选填,它表示创建该 DataView 时的长度,当不传递默认时表示匹配 buffer 的长度。
// 创建8个字节长度的缓存冲
const buffer = new ArrayBuffer(8);

// 根据传入的buffer 从第一个字节开始,并且字节长度为匹配buffer的长度
const dataView = new DataView(buffer);

// 将DataView中偏移量为0个字节的字节,也就是第一个字节设置为十进制的1
dataView.setUint8(0, 1);
// 将DataView中偏移量为1个字节的字节,也就是第二个字节设置为十进制的2
dataView.setUint8(1, 2);

// 从dataView中偏移第0个字节,也就是第一个字节,获取8位
// log: 1
dataView.getUint8(0);

// 从dataView中偏移第一个字节获取八位,也就是获取第二个字节的值
// log: 2
dataView.getUint8(1);

// 偏移量为0个字节,获取后续16位大小(也就是获取前两个字节大小)
// log: 258
dataView.getUint16(0);

// 偏移量为2个字节,设置后16位大小为256(也就是设置第三个字节和第四个字节大小和为256)
dataView.setUint16(2, 256);

// 偏移量为2个字节,获取后16位大小
// log: 256
dataView.getUint16(2);



  • 分别将第一个字节(8位)的值变为 1 和将第二个字节变为 10 进制的 2。

js Blob、ArrayBuffer(Uint8Array、TypedArray、DataView)、Buffer、DataUrl_第9张图片
js Blob、ArrayBuffer(Uint8Array、TypedArray、DataView)、Buffer、DataUrl_第10张图片

  • 服务器返回二进制数据
et xhr = new XMLHttpRequest();
xhr.open('GET', someUrl);
xhr.responseType = 'arraybuffer';

xhr.onload = function () {
  let arrayBuffer = xhr.response;
  // ···
};

xhr.send();

Buffer:
即缓存,去存储这些暂时用不上的数据(传的比 cpu 处理快,这个位置就存着提前到达的数据;比 cpu 处理慢,这个位置就存够一批足够能用的数据再给 cpu)这个区域就称之为缓存区(Buffer),一般是内存空间作为缓存空间。

node中的Buffer:
是 Uint8Array 类的子类,除了 Buffer 对象之外,Stream 和 Readline 也是比较常用的 node 内置二进制处理模块,使用这种二进制处理模块比常规的数组更快捷
js Blob、ArrayBuffer(Uint8Array、TypedArray、DataView)、Buffer、DataUrl_第11张图片

// Node端(Koa)
const app = new Koa();
app.use(async (ctx, next) => {
    if (ctx.path === '/ajax') {
        const chunks = [];
        const req = ctx.req;
        req.on('data', buf => {
            chunks.push(buf);
        })
        req.on('end', () => {
            let buffer = Buffer.concat(chunks);
            console.log(buffer.toString())
        })
    }
});
app.listen(3000)

// 前端
const xhr = new XMLHttpRequest();
xhr.open("POST", "ajax", true);
xhr.setRequestHeader('Content-Type', 'text/plain')
xhr.send("asdasdsadfsdfsadasdas");

运行结果
// 创建10个字节大小的空buffer
const buf1 = Buffer.alloc(10);

// 根据内容直接创建buffer
const buf2 = Buffer.from("hello buffer")

//将数据进行Unicode编码并展示
buf2.toJSON()

//buffer的大小
buf2.length	 //12

//写入数据到buffer
buf1.write("Buffer really rocks!")

//解码buffer
buf1.toString()	// 'Buffer rea' buf1只有十个字节大小

关系及转换

  • 字符串 → Uint8Array
    var str = 'ab';
    console.log(Uint8Array.from(str.split(''), (e) => e.charCodeAt(0))); // Uint8Array(2) [97, 98]
  • Uint8Array → 字符串
    var u8 = Uint8Array.of(97, 98);
    console.log(Array.from(u8, (e) => String.fromCharCode(e)).join('')); // ab
  • 字符串 → DataUrl
    var str = 'ab';
    console.log('data:application/octet-stream;base64,' + btoa(str)); // data:application/octet-stream;base64,YWI=
  • DataUrl -> 字符串
    var data = 'data:application/octet-stream;base64,YWI=';
    console.log(atob(data.split(',')[1])); // ab
  • Uint8Array -> ArrayBuffer
    var u8 = Uint8Array.of(1, 2);
    console.log(u8.buffer); // ArrayBuffer(2) {}
  • ArrayBuffer -> Uint8Array
    var buffer = new ArrayBuffer(2);
    console.log(new Uint8Array(buffer)); // Uint8Array(2) [0, 0]
  • ArrayBuffer -> DataView
    var buffer = new ArrayBuffer(2);
    var dataView = new DataView(buffer, 0); // DataView(2) {}
  • DataView -> ArrayBuffer
    console.log(dataView.buffer); // ArrayBuffer(2) {}
  • ArrayBuffer → Blob
    var buffer = new ArrayBuffer(32);
    var blob = new Blob([buffer]);  // Blob {size: 32, type: ""}
  • UintXXArray → Blob
    var u8 = Uint8Array.of(97, 32, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33);
    var blob = new Blob([u8]);
  • 字符串 → Blob
    var blob = new Blob(['Hello World!'], {type: 'text/plain'}); // Blob {size: 12, type: "text/plain"}
  • DataUrl -> blob
    var data = 'data:application/octet-stream;base64,YWI=';
    function dataURLtoBlob(dataurl) {
      var arr = dataurl.split(','),
        mime = arr[0].match(/:(.*?);/)[1],
        bstr = atob(arr[1]),
        n = bstr.length,
        u8arr = new Uint8Array(n);

      while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
      }
      return new Blob([u8arr], { type: mime });
    }
    console.log(dataURLtoBlob(data)); // Blob {size: 2, type: "application/octet-stream"}

js Blob、ArrayBuffer(Uint8Array、TypedArray、DataView)、Buffer、DataUrl_第12张图片

你可能感兴趣的:(javaScript,javascript,前端,开发语言)