File和blob对象学习

104 阅读8分钟

浏览器对象-File

v2-ed143b043805e01fbbea5712c7e27789_720w.webp

ArrayBuffer和Blob对象

wangdoc.com/javascript/…

zhuanlan.zhihu.com/p/97768916

ArrayBuffer

ArrayBuffer 对象表示一段二进制数据,用来模拟内存里面的数据。通过这个对象,JavaScript 可以读写二进制数据。

 var buffer = new ArrayBuffer(8);

上面代码中,实例对象buffer占用8个字节。

ArrayBuffer 对象有实例属性byteLength,表示当前实例占用的内存长度(单位字节)。

 var buffer = new ArrayBuffer(8);
 buffer.byteLength // 8

ArrayBuffer 对象有实例方法slice(),用来复制一部分内存。它接受两个整数参数,分别表示复制的开始位置(从0开始)和结束位置(复制时不包括结束位置),如果省略第二个参数,则表示一直复制到结束。

 var buf1 = new ArrayBuffer(8);
 var buf2 = buf1.slice(0);

上面代码表示复制原来的实例。

Blob

developer.mozilla.org/zh-CN/docs/…

Blob 对象表示一个二进制文件的数据内容,比如一个图片文件的内容就可以通过 Blob 对象读写。它通常用来读写文件,它的名字是 Binary Large Object (二进制大型对象)的缩写。它与 ArrayBuffer 的区别在于,它用于操作二进制文件,而 ArrayBuffer 用于操作内存。

Blob构造
 new Blob(array [, options])

Blob构造函数接受两个参数。

  • 第一个参数是数组,成员是字符串或二进制对象,表示新生成的Blob实例对象的内容;
  • 第二个参数是可选的,是一个配置对象,目前只有一个属性type,它的值是一个字符串,表示数据的 MIME 类型,默认是空字符串
 var htmlFragment = ['<a id="a"><b id="b">hey!</b></a>'];
 var myBlob = new Blob(htmlFragment, {type : 'text/html'});
 上面代码中,实例对象myBlob包含的是字符串。生成实例的时候,数据类型指定为text/html。
 ​
 下面是另一个例子,Blob 保存 JSON 数据。
 var obj = { hello: 'world' };
 var blob = new Blob([ JSON.stringify(obj) ], {type : 'application/json'});
Blob实例属性和实例方法
  • Blob具有两个实例属性sizetype,分别返回数据的大小和类型。

     var htmlFragment = ['<a id="a"><b id="b">hey!</b></a>'];
     var myBlob = new Blob(htmlFragment, {type : 'text/html'});
     ​
     myBlob.size // 32
     myBlob.type // "text/html"
    
  • Blob具有一个实例方法slice,用来拷贝原来的数据,返回的也是一个Blob实例。

     myBlob.slice(start, end, contentType)
    

File对象

wangdoc.com/javascript/…

developer.mozilla.org/zh-CN/docs/…

File 对象代表一个文件,用来读写文件信息。它继承了 Blob 对象,或者说是一种特殊的 Blob 对象,所有可以使用 Blob 对象的场合都可以使用它。

最常见的使用场合是表单的文件上传控件(<input type="file">),用户选中文件以后,浏览器就会生成一个数组,里面是每一个用户选中的文件,它们都是 File 实例对象。

 // HTML 代码如下
 // <input id="fileItem" type="file">
 var file = document.getElementById('fileItem').files[0];
 file instanceof File // true

上面代码中,file是用户选中的第一个文件,它是 File 的实例。

构造函数

浏览器原生提供一个File()构造函数,用来生成 File 实例对象。

 new File(array, name [, options])

File()构造函数接受三个参数。

  • array:一个数组,成员可以是二进制对象或字符串,表示文件的内容。

  • name:字符串,表示文件名或文件路径。

  • options:配置对象,设置实例的属性。该参数可选。

    • 第三个参数配置对象,可以设置两个属性。

      • type:字符串,表示实例对象的 MIME 类型,默认值为空字符串。
      • lastModified:时间戳,表示上次修改的时间,默认为Date.now()

下面是一个例子。

 var file = new File(
   ['foo'],
   'foo.txt',
   {
     type: 'text/plain',
   }
 );

实例属性和实例方法

File 对象有以下实例属性。

  • File.lastModified:最后修改时间
  • File.name:文件名或文件路径
  • File.size:文件大小(单位字节)
  • File.type:文件的 MIME 类型
 var myFile = new File([], 'file.bin', {
   lastModified: new Date(2018, 1, 1),
 });
 myFile.lastModified // 1517414400000
 myFile.name // "file.bin"
 myFile.size // 0
 myFile.type // ""

上面代码中,由于myFile的内容为空,也没有设置 MIME 类型,所以size属性等于0,type属性等于空字符串。

File 对象没有自己的实例方法,由于继承了 Blob 对象,因此可以使用 Blob 的实例方法slice()

FileList 对象

FileList对象是一个类似数组的对象,代表一组选中的文件,每个成员都是一个 File 实例。它主要出现在两个场合。

  • 文件控件节点(<input type="file">)的files属性,返回一个 FileList 实例。
  • 拖拉一组文件时,目标区的DataTransfer.files属性,返回一个 FileList 实例。
 // HTML 代码如下
 // <input id="fileItem" type="file">
 var files = document.getElementById('fileItem').files;
 files instanceof FileList // true

FileReader 对象

FileReader 对象用于读取 File 对象或 Blob 对象所包含的文件内容。

浏览器原生提供一个FileReader构造函数,用来生成 FileReader 实例。

 var reader = new FileReader();

FileReader 有以下的实例属性。

  • FileReader.error:读取文件时产生的错误对象
  • FileReader.readyState:整数,表示读取文件时的当前状态。一共有三种可能的状态,0表示尚未加载任何数据,1表示数据正在加载,2表示加载完成。
  • FileReader.result:读取完成后的文件内容,有可能是字符串,也可能是一个 ArrayBuffer 实例。
  • FileReader.onabort:abort事件(用户终止读取操作)的监听函数。
  • FileReader.onerror:error事件(读取错误)的监听函数。
  • FileReader.onload:load事件(读取操作完成)的监听函数,通常在这个函数里面使用result属性,拿到文件内容。
  • FileReader.onloadstart:loadstart事件(读取操作开始)的监听函数。
  • FileReader.onloadend:loadend事件(读取操作结束)的监听函数。
  • FileReader.onprogress:progress事件(读取操作进行中)的监听函数。

下面是监听load事件的一个例子。

 // HTML 代码如下
 <input type="file" onchange="onChange(event)">
 ​
 function onChange(event) {
   var file = event.target.files[0];
   var reader = new FileReader();
   reader.readAsDataURL(file)
   reader.onload = function (event) {
     console.log(event.target.result)
     $('#pdf').css('display','block')
     $('#pdf').attr('src',event.target.result)
   };
 ​
   reader.readAsText(file);
 }

上面代码中,每当文件控件发生变化,就尝试读取第一个文件。如果读取成功(load事件发生),就打印出文件内容。

FileReader 有以下实例方法。

  • FileReader.abort():终止读取操作,readyState属性将变成2
  • FileReader.readAsArrayBuffer():以 ArrayBuffer 的格式读取文件,读取完成后result属性将返回一个 ArrayBuffer 实例。
  • FileReader.readAsBinaryString():读取完成后,result属性将返回原始的二进制字符串。
  • FileReader.readAsDataURL():读取完成后,result属性将返回一个 Data URL 格式(Base64 编码)的字符串,代表文件内容。对于图片文件,这个字符串可以用于<img>元素的src属性。注意,这个字符串不能直接进行 Base64 解码,必须把前缀data:*/*;base64,从字符串里删除以后,再进行解码。
  • FileReader.readAsText():读取完成后,result属性将返回文件内容的文本字符串。该方法的第一个参数是代表文件的 Blob 实例,第二个参数是可选的,表示文本编码,默认为 UTF-8。

API

readAsDataURL

 const reader = new FileReader();
 reader.readAsDataURL(file);

createObjectURL

获取当前文件流blob或文件file的一个内存URL

 let url = URL.createObjectURL(file.raw)
 ​
 let url = URL.createObjectURL(blob) 

应用场景

图片,base64,file,Blob转换

juejin.cn/post/684490…

blog.csdn.net/qq_42966167…

  • Base64 转 File

     export const base64ToFile = (base64, mime, filename) => {
       let arr = base64.split(',')
       let type = mime || arr[0].match(/:(.*?);/)[1]
       let suffix = mine.split('/')[1]
       let fileName = filename || `未命名.${suffix}`
       let bstr = atob(arr[1])
       let n = bstr.length
       let u8arr = new Uint8Array(n)
       while (n--) {
         u8arr[n] = bstr.charCodeAt(n)
       }
       return new File([u8arr], fileName, { type })
     }
     ​
    

获取blob文件流并下载

由于是封装的axios,需要在接口的请求头header设置返回格式 responseType: "blob" 这样与后端配合可以得到文件流格式的返回 也就是这个样子

通过URL.createObjectURL(blob)可以获取当前文件的一个内存URL

 preview(id).then(res => {
     let url = window.URL.createObjectURL(new Blob([res], { type: 'application/pdf' }))//获得一个pdf的url对象
     window.open(url, '_blank')//打开一个新窗口
     URL.revokeObjectURL(url) //释放内存
 })

在每次调用 createObjectURL() 方法时,都会创建一个新的 URL 对象,即使你已经用相同的对象作为参数创建过。当不再需要这些 URL 对象时,每个对象必须通过调用 URL.revokeObjectURL() 方法来释放。

浏览器在 document 卸载的时候,会自动释放它们,但是为了获得最佳性能和内存使用状况,你应该在安全的时机主动释放掉它们。

 //下载zip
 downLoad(id).then((res) => {
   const elink = document.createElement('a') //创建个a链接元素
   elink.href = window.URL.createObjectURL(new Blob([res], { type: `application/zip` }))//获得一个zip的url对象
   elink.style.display = 'none'
   elink.setAttribute('download', this.downName) //文件名
   document.body.appendChild(elink)
   elink.click() //触发点击方法
   URL.revokeObjectURL(elink.href) // 释放URL对象
   document.body.removeChild(elink) //释放节点
 })

PDF转图片

pdfjs下载地址:github.com/mozilla/pdf…

需要下载,pdf.js,pdf.worker.js

 let url = window.URL.createObjectURL(file.raw) 
 //获取pdf第一页并转图像 
 pdfjsLib.getDocument(url).promise.then(pdf => { 
   pdf.getPage(1).then(page => { 
       const canvas = document.createElement('canvas'); 
       const context = canvas.getContext('2d'); 
  
       const viewport = page.getViewport({ scale: 1.5 }); 
  
       canvas.width = viewport.width; 
       canvas.height = viewport.height; 
  
       const renderContext = { 
           canvasContext: context, 
           viewport: viewport 
       }; 
  
       page.render(renderContext).promise.then(() => { 
           const imageDataURL = canvas.toDataURL('image/png'); //base64地址
           const image = new Image(); 
           image.src = imageDataURL; 
           document.getElementById('img').appendChild(image); 
       }).catch(error => { 
           console.error(error); 
       }); 
   }).catch(error => { 
       console.error(error); 
   }); 
 }).catch(error => { 
     console.error(error); 
 });

base64图片转文件并上传

 // base64转二进制流(blob) 
 function dataURLtoBlob(dataurl) { 
 let arr = dataurl.split(',') 
   let mime = arr[0].match(/:(.*?);/)[1] 
   let bstr = atob(arr[1]) 
   let n = bstr.length 
   let u8arr = new Uint8Array(n) 
   while (n--) { 
     u8arr[n] = bstr.charCodeAt(n) 
   } 
   return new Blob([u8arr], { type: mime }) 
 } 
 ​
 const uploadFile = async(imageDataURL)=>{ 
   //文件上传到服务器 
   const imageBlob =await dataURLtoBlob(imageDataURL); 
   //因为blob上传是没有文件名的,所以需要转成file对象
   const imageFile = new File([imageBlob], file.name); 
   const formData = new FormData(); 
   formData.append('file', file); 
   formData.append('appId',this.pageConfig.appId) 
   const res = await this.uploadFile(formData) 
 }