当前位置: 首页 > 科技观察

谁说前端不需要懂二进制

时间:2023-03-21 10:10:39 科技观察

作为前端,在工作中也会遇到很多与二进制处理相关的需求,比如导出EXCEL表格,生成PDF,打包多个文件,以及处理音频。一般来说,前端代表UI层,其对外表现是人类可读的,而服务器代表数据层,是机器可读的。如果把EXCEL和PDF的处理交给服务端,那么服务端难免要做一层格式化逻辑来和前端保持一致。一是增加了复杂度,二是容易造成前端和服务端的数据不一致。这时,为了降低复杂度,工作量可能会尽可能在浏览器端完成。本文总结了浏览器端二进制与相关数据之间的转换,如ArrayBuffer、TypedArray、Blob、DataURL、ObjectURL、Text之间的转换。为了更好的理解和方便以后的查询,我特意做了一张图来总结一下。二进制相互转换图二进制相关数据类型在介绍常见的二进制数据处理之前,先简单介绍一下二进制相关的几种数据类型ArrayBuffer&&TypedArrayTypedArray是一种ES6+新的类数组数据结构,用于描述二进制数据。但它本身不能被实例化甚至访问。你可以理解为抽象类或接口。基于TypedArray,有以下几种数据类型:Uint8ArrayUint和UnsignedInt表示数组的每一项都是无符号整数8表示每一项数据占8位,即一个字节Int8ArrayUint16ArrayInt16Array...通过Uint8Array,就可以知道Uint16Array和Int8Array所代表的含义了。constarray=newInt32Array([1,2,3])//.length表示数组的大小//3array.length//.btyeLength表示数据的字节大小//12array.byteLengthArrayBuffer表示二进制数据结构,"和只读的”,需要转换为TypedArray才能写入。constarray=newInt16Array([1,2,3])//TypedArray->ArrayBufferarray.buffer//ArrayBuffer->TypedArraynewInt16Array(array.buffer)//buffer.length表示数据array占用的字节大小。buffer.length===array.byteLength连接多个TypedArraysTypedArray没有Array.prototype.concat方法可以像数组一样连接多个TypedArray。但是,它提供了TypedArray.prototype.set可以用来间接连接字符串?可以参考MDN文档:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/set?//在位移offset位置放置typedarraytypedarray.set(typedarray,offset)的原理是分配一个足够的空间容纳要连接的TypedArray,然后叠加functionconcatenate(constructor,...arrays){letlength=0;for(letarrofarrays){length+=arr.length;}letresult=newconstructor(length);letoffset=0;for(letarrofarrays){result.set(arr,offset);offset+=arr.length;}returnresult;}concatenate(Uint8Array,newUint8Array([1,2,3]),newUint8Array([4,5,6]))同时你还需要对资源获取有个大概的了解,比如XHR,抓取,文件上传。BlobBlob是浏览器端的类文件对象。操作blob需要数据类型FileReader。FileReader有以下方法,可以将Blob转换成其他数据文件大小blob.sizeconstarray=newUint8Array([128,128,128])constblob2=newBlob([array])functionreadBlob(blob,type){returnnewPromise(resolve=>{constreader=newFileReader()reader.onload=function(e){resolve(e.target.result)}reader.readAsArrayBuffer(blob)})}readBlob(blob,'DataURL').then(url=>console.log(url))数据输入数据输入或者资源请求可以分为下面两种types方法通过url地址请求网络资源通过文件上传请求本地资源fetchfetch大家应该不陌生,但是大多使用单一环境,一般用于请求json数据。其实《它也可以设置返回数据格式为Blob或者ArrayBuffer。"fetch返回一个包含Response对象的Promise,Response有如下方法Response.prototype.arrayBufferResponse.prototype.blobResponse.prototype.textResponse.prototype.json?详见MDN文档https://developer.mozilla.org/en-US/docs/Web/API/Response?fetch('/api/ping').then(res=>{//trueconsole.log(resinstanceofResponse)//最常用的returnres。json()//ReturnBlob//returnres.blob()//ReturnArrayBuffer//returnres.arrayBuffer()})另外,万能的ResponseAPI可以使用TypedArray,Blob,Text作为输入输出。”这意味着这三种数据类型的转换可以通过Response"xhr"xhr可以设置responseType来接收合适的数据类型"constrequest=newXMLHttpRequest()request.responseType='arraybuffer'request.responseType='blob'FilelocalFiles即可通过input[type=file]上传。上传成功后,可以通过docume获取上传的文件nt.getElementById('input').files[0],即一个File对象,它是Blob的一个子类。可以通过FileReader或Response获取文件内容。数据输出称为数据显示或下载。数据经过二进制处理后可以用url表示,然后通过图片、视频等元素直接引用或下载。数据URL数据URL是数据作为URL。因此,“如果资源太大,地址就会很长”。用以下形式表示。data:[][;base64],首先你好,世界。将以下地址粘贴到地址栏,你将访问hello,worlddata:text/html,

Hello%2C%20World!

Base64编码与解码Base64使用大小写字母、数字、+和/64characters对数据进行编码,所以称为Base64。编码后,文字大小会变大1/3。在浏览器中,您可以使用atob和btoa编码来解码数据。//aGVsbG8=btoa('hello')ObjectURL可以使用浏览器的新APIURL对象生成一个地址来表示Blob数据。//粘贴生成的地址,可以访问hello,world//blob:http://host/27254c37-db7a-4f2f-8861-0cf9aec89a64URL.createObjectURL(newBlob('hello,world'.split('')))下载数据:application/octet-stream;base64,5bGx5pyI资源下载可以使用FileSaver[1]。这里还有一个简单的函数下载链接functiondownload(url,name){consta=document.createElement('a')a.download=namea.rel='noopener'a.href=url//触发模拟点击a.dispatchEvent(newMouseEvent('click'))//ora.click(}BinarydataconversionBinarydataconversion以上是二进制数据之间的转换图,有的转换可以直接通过API传递,有的需要代码。下面是几个常见的String到TypedArray的转换代码根据上图,string到TypedArray的转换可以通过“String->Blob->ArrayBuffer->TypedArray”的路径完成。关于代码中的函数readBlob,可以把link数据类型转回去——Blob[2]constname='MountainMoon'constblob=newBlob(name.split(''))readBlob(blob,'ArrayBuffer').then(buffer=>newUint8Array(buffer))也可以直接通过ResponseAPI"String->ArrayBuffer->TypedArray"constname='山岳'newResponse(name).arrayBuffer(buffer=>newUint8Array(buffer))以上两种方法都是直接通过API来转换的,如果你想了解如何手动将字符串和二进制TypedArrayString转换为TypedArray2使用enodeURIComponent将字符串转换为utf8,然后构造TypedArray。functionstringToTypedArray(s){conststr=encodeURIComponent(s)constbinstr=str.replace(/%([0-9A-F]{2})/g,(_,p1)=>{returnString.fromCharCode('0x'+p1)})returnnewUint8Array(binstr.split('').map(x=>x.charCodeAt(0)))}实践一、如何从整理出来的转换图上传本地图片并显示在网页上多于。上传图片->Blob->对象URL2。上面整理的转换图如何拼接两个音频文件获取路由fetch请求音频资源->ArrayBuffer->TypedArray->拼接成TypedArray->ArrayBuffer->Blob->ObjectURL3。如何将json数据转换成demo.json并下载文件。JSON被认为是一个字符串。从上面整理的转换图来看,Text->DataURL路径除了DataURL外,还可以转换成ObjectURL进行下载。下载功能下载可以参考上面的链接DataOutput-Download[3]Text->Blob->ObjectURL可以直接在控制台粘贴以下代码下载文件constjson={a:3,b:4,c:5}conststr=JSON.stringify(json,null,2)//方案一:Text->DataURLconstdataUrl=`data:,${str}`download(dataUrl,'demo.json')//方案二:Text->Blob->ObjectURLconsturl=URL.createObjectURL(newBlob(str.split('')))download(url,'demo1.json')