Js:Blob、ArrayBuffer、FileReader、URL、Image、关于文件下载的方法案例

目录

概括

1. 基本概念

1.1 Blob:存储二进制文件的“容器”。不可变。

1.2 File:File接口基于Blob

1.3 ArrayBuffer :表示原始的二进制数据缓冲区

1.4 FileReader:异步文件读取,可进行文件类型转换

1.5 URL.createObjectURL():file转成url

1.6 new Image():生成一个尚未被插入 DOM 树中的 img标签

2. 基本功能

2.1 Blob、File可实现的功能

在这里插入图片描述

2.2 ArrayBuffer可实现的功能

在这里插入图片描述

2.3 Blob(File)和ArrayBuffer区别

  • 除非你需要使用 ArrayBuffer 提供的写入/编辑的能力,否则 Blob 格式可能是最好的。

  • Blob 对象是不可变的,而 ArrayBuffer 是可以通过 TypedArrays 或 DataView 来操作。

  • ArrayBuffer 是存在内存中的,可以直接操作。而 Blob 可以位于磁盘、高速缓存内存和其他不可用的位置。

  • Blob 与 ArrayBuffer 对象之间是可以相互转化的

    • 使用 FileReader 的 readAsArrayBuffer() 方法,可以把 Blob 对象转换为 ArrayBuffer 对象;
    • 使用 Blob 构造函数,如 new Blob([new Uint8Array(data]);,可以把 ArrayBuffer 对象转换为 Blob 对象。

2.4 FileReader可实现的功能

在这里插入图片描述

2.5 URL.createObjectURL()可实现的功能

URL.createObjectURL()也是生成URL。
其方法的参数是Blob对象/File对象。
其返回值格式是blob:开头的地址。比如:blob:http://172.19.40.138:2023/eff2f372-3690-4862-8223-1a1e15150ae0

3. 小结(先看↓↓↓↓↓↓↓)

  1. Blob(File)ArrayBuffer 都是文件“容器”。能用Blob就不用ArrayBuffer,除非需要写入/编辑的功能

  2. FileReaderURL.createObjectURL()都可以将Blob(File)转为URL

    • 区别是URL的前缀不一样。
      • 【FileReader】是data:URL(Base64字符串)
      • 【URL.createObjectURL()】是blob:域名/...
    • Data URL 和 Blob URL区别。
      • 格式不同
      • 长度不同,Data URL 中嵌入了资源内容,一般会很长。Blob URL 一般较短。
      • Blob URL 只能在当前应用内部使用,把Blob URL复制到浏览器的地址栏中,是没法获取数据的。Data URL相比之下,就有很好的移植性,你能够在任意浏览器中使用。
      • 除了可以用作图片资源的网络地址,Blob URL也可以用作其他资源的网络地址,例如html文件、json文件等,为了保证浏览器能正确的解析Blob URL返回的文件类型,需要在创建Blob对象时指定相应的type。
        // 创建HTML文件的Blob URL
        var data = "<div style='color:red;'>This is a blob</div>";
        var blob = new Blob([data], { type: 'text/html' });
        var blobURL = URL.createObjectURL(blob);
        
        // 创建JSON文件的Blob URL
        var data = { "name": "abc" };
        var blob = new Blob([JSON.stringify(data)], { type: 'application/json' });
        var blobURL = URL.createObjectURL(blob);
        
  3. new Image():生成一个尚未被插入 DOM 树中的 img标签

4. Vue前端下载文件,后端返回流的形式

4.1 axios.js请求封装:注意事项

// response响应拦截
instance.interceptors.response.use(
  // 不能这样拦截,没法获取header,获取不到必要信息
  // ({ data }) => {
  //   return data
  // },
  (res) => {
    return res.data
  },
  (error) => {
    return Promise.reject(error)
  }
)

4.2 通过Blob直接下载

// 发送请求处理
// exportFile是请求,config里设置{ responseType: 'blob' }
exportFile(obj, { responseType: 'blob' }).then(res => {
  console.log(res, '---res')
  const data = res.data
  const url = window.URL.createObjectURL(new Blob([data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })) // 文件类型是xlsx
  // 获取返响应头里的文件名,需要自己切割
  let dis = res.headers['content-disposition']
  let fileName = dis.split('attachment;filename=')[1]
  // 如果fileName中包含 中文
  fileName = decodeURIComponent(fileName)
  // 通过a标签下载
  const link = document.createElement('a')
  link.style.display = 'none'
  link.href = url
  link.setAttribute('download', fileName||'excel.xlsx')
  document.body.appendChild(link)
  link.click()
  document.body.removeChild(link)
})

注意:

  1. res.headers[‘content-disposition’],其值是如下类型字符串 attachment;filename=xxx.xlsx,需要自己切分。
  2. 如果文件名是中文则需要后端配合转码,后端在发送文件时,要将文件名进行java.net.URLEncoder.encode(fileName, “UTF8”) 转码,否则前端接收到的 res.headers[‘content-disposition’] 的中文信息是乱码的。后端转码后,前端通过decodeURIComponent 解码即可
    • 在后台这样处理 :String msg = URLEncoder.encode("中文", "UTF-8").replace("+","%20")
    • 在前台这样处理:decodeURIComponent(msg)
  3. 如果获取不到headers['content-disposition']的话,需要后端对该接口配置一下Header
    • 在controller层中的二进制流文件下载方法下配置放行属性
    • response.setHeader("Access-Control-Expose-Headers", "content-disposition");
4.2.1 new Blob() 不同文件类型的 type 值
const url = window.URL.createObjectURL(new Blob([data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })) 

其中的type值可以根据不同的文件类型进行设置。详情可以通过以下链接参考:

Blob的type类型
base64的前缀

4.3 通过Blob+FileReader的方式下载

const blob = res
const reader = new FileReader()
reader.readAsDataURL(blob)
reader.onload = function (ev) {
  if (window.navigator.msSaveOrOpenBlob) {
    // 兼容ie11
    const blobObject = new Blob([blob])
    window.navigator.msSaveOrOpenBlob(blobObject, '文件名称.xlsx')
  } else {
    const url = URL.createObjectURL(new Blob([blob]))
    const a = document.createElement('a')
    document.body.appendChild(a) // 此处增加了将创建的添加到body当中
    a.href = url
    a.download = '文件名称名称.xlsx'
    a.target = '_blank'
    a.click()
    a.remove() // 将a标签移除
  }
}

一、Blob对象

Blob(binary large object),二进制类文件大对象,是一个可以存储二进制文件的“容器”,HTML5中的Blob对象除了存放二进制数据外还可以设置这个数据的MIME类型。
File接口基于Blob,继承了 blob 的功能并将其扩展使其支持用户系统上的文件。

1. Blob构造函数

new Blob([data], {type: "application/octet-binary"})

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

  • 第一个参数是一个包含实际数据的数组,
  • 第二个参数是数据的MIME类型。

2. Blob属性

2.1 Blob.size

  • blob对象的数据大小

2.2 Blob.type

  • 表示blob对象所包含数据的MIME类型。如果实例化时未指明类型,则该值为空字符串。

3. Blob方法

3.1 Blob.slice()

  • 相当于数组Array.slice方法,表示截取指定范围的数据,形成新的blob对象。(用于文件的分割上传)

3.2 Blob.arrayBuffer()

  • 返回一个 Promise 对象且包含 blob 所有内容的二进制格式的 ArrayBuffer。(Blob转成ArrayBuffer)

二、File对象

1. 前言

File指本地文件系统中的文件。File对象提供有关文件的信息,并允许网页中的 JavaScript 访问其内容。

File是一个具有名字同时可能也有一个修改日期的Blob。

获取方式
可以从一个由 <input type="file"/> 元素组成的 files 数组中获取,或者从一个由与 drop 事件的 Event 对象关联的 DataTransfer 对象组成的 files 数组中,取得一个用户选择的文件。

2. 构造函数

var myFile = new File(bits, name[, options]);

返回一个新构建的文件对象(File)。

参数:

  1. bitsArrayBufferArrayBufferViewBlob,或者 DOMString对象的 Array — 或者任何这些对象的组合。这是 UTF-8 编码的文件内容。
  2. name:USVString,表示文件名称,或者文件路径。
  3. options: 可选。配置属性。可用的选项如下:
    • type: 表示将要放到文件中的内容的 MIME 类型。默认值为 “” 。
    • lastModified: 表示文件最后修改时间的 Unix 时间戳(毫秒)。默认值为 Date.now()。

示例:

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

3. 属性

file.lastModified
当前文件最后的修改时间,自 UNIX 时间起始值(1970年1月1日 00:00:00 UTC)以来的毫秒数。

file.name
当前文件的文件名(不包括路径)。

file.size
文件的大小。

file.type
文件的 MIME Type。

三、FileReader

1. 前言

FileReader是一种异步文件读取机制,结合input:file可以很方便的读取本地文件。

2. 构造函数

new FileReader()

2.1 构造函数的属性

属性描述
error(只读)一个DOMException(异常),表示在读取文件时发生的错误 。
readyState(只读)表示FileReader状态的数字,取值如下表。
result(只读)文件的内容。该属性仅在读取操作完成后才有效,数据的格式取决于使用哪个方法来启动读取操作。
(1)readyState状态的属性
常量名描述
EMPTY0还没有加载任何数据。
LOADING1数据正在被加载。
DONE2已完成全部的读取请求。

3. 方法

方法描述
abort():void中止读取操作。在返回时,readyState属性为DONE
readAsArrayBuffer(file):void读取文件后,result 属性中保存的是被读取文件的 ArrayBuffer 数据对象。
readAsBinaryString(file):void读取文件后,result属性中包含所读取文件的原始二进制数据。
readAsDataURL(file):void读取文件后,result属性中将包含一个data: URL 格式的 Base64 字符串以表示所读取文件的内容。
readAsText(file):void读取文件后,result属性中将包含一个字符串以表示所读取的文件内容。

4. 事件

事件名称描述
onabort当读取操作被中止时调用
onerror当读取操作发生错误时调用
onload当读取操作成功完成时调用
onloadend当读取操作完成时调用,不管是成功还是失败
onloadstart当读取操作将要开始之前调用
onprogress在读取数据过程中周期性调用

注意:文件一旦开始读取,无论成功或失败,实例的 result 属性都会被填充。如果读取失败,则 result 的值为 null ,否则即是读取的结果,绝大多数的程序都会在成功读取文件的时候,抓取这个值。

5. 基础案例

5.1 读取txt文件

<template>
  <div class="emqrcode">
    <a-upload :file-list="fileList" :before-upload="beforeUpload">
      <a-button> <a-icon type="upload" /> Select File </a-button>
    </a-upload>
    <div>------------------------------</div>
    <div ref="div"></div>
  </div>
</template>

<script>
export default {
  data () {
    return {
      fileList: []
    }
  },
  methods: {
    beforeUpload (file) {
      this.fileList = [...this.fileList, file]
      console.log(file, '上传的文件')
      const reader = new FileReader()
      reader.readAsText(file, 'utf8') // file文件
      reader.onload = (e) => {
        console.log(e, '读取文件成功的e')
        const data = e.target.result
        this.$refs.div.innerHTML += data // reader.result和e.target.result是一个东西
        // this.$refs.div.innerHTML += reader.result // reader.result为获取结果
      }
      return false
    }
  }
}
</script>

<style lang="less"></style>

5.2 读取Excel文件(结合xlsx.js使用)

<template>
  <div class="emqrcode">
    <a-upload :file-list="fileList" :before-upload="beforeUpload">
      <a-button> <a-icon type="upload" /> Select File </a-button>
    </a-upload>
    <div>------------------------------</div>
    <div ref="div"></div>
  </div>
</template>

<script>
import XLSX from 'xlsx'

export default {
  data () {
    return {
      fileList: []
    }
  },
  methods: {
    file2Xce (file) {
      return new Promise(function (resolve, reject) {
        const reader = new FileReader()
        // 读取为二进制字符串
        reader.readAsBinaryString(file)
        reader.onload = function (e) {
          const data = e.target.result
          // XLSX.read解析数据,按照type 的类型解析
          this.wb = XLSX.read(data, {
            type: 'binary' // 二进制
          })
          console.log(this.wb, '---->解析后的数据')
          const result = []
          // 工作表名称的有序列表
          console.log(this.wb.SheetNames, '---->工作表名称数组')
          this.wb.SheetNames.forEach(sheetName => {
            result.push({
              // 工作表名称
              sheetName: sheetName,
              // 包含表数据的 数组(数据导出)
              sheet: XLSX.utils.sheet_to_json(this.wb.Sheets[sheetName]) // this.wb.Sheets[sheetName]单工作表文件的第一个工作表
            })
          })
          console.log(result, '----->表数据的数组')
          resolve(result)
        }
      })
    },
    beforeUpload (file) {
      this.fileList = [...this.fileList, file]
      console.log(file, '上传的文件')
      console.log(file.raw)
      this.file2Xce(file).then((res) => {
        console.log(res, 'resolve结果')
        console.log('可以继续对res数据进行二次处理')
        // 整理数据格式,只保留x和y
        // if (xyToFormat(res)) {
        //   this.resList = xyToFormat(res)
        //   this.$emit('excelBeforeUploadEmit', file, this.resList)
        // } else {
        //   this.resList = []
        // }
      })
      return false
    }
  }
}
</script>

<style lang="less"></style>

5.3 读取图片文件(也可以实现图片预览)

<template>
  <div class="emqrcode">
    <a-upload :file-list="fileList" :before-upload="beforeUpload">
      <a-button> <a-icon type="upload" /> Select File </a-button>
    </a-upload>
    <div>------------------------------</div>
    <div ref="div"></div>
  </div>
</template>

<script>
export default {
  data () {
    return {
      fileList: []
    }
  },
  methods: {
    beforeUpload (file) {
      this.fileList = [...this.fileList, file]
      console.log(file, '上传的文件')
      const reader = new FileReader()
      reader.readAsDataURL(file) // 读取图片
      reader.onload = (e) => {
        console.log(e, '读取文件成功的e')
        const img = new Image()
        img.src = reader.result
        console.log(reader.result, '----->data: URL 格式的 Base64 字符串')
        this.$refs.div.appendChild(img)
      }
      return false
    }
  }
}
</script>

<style lang="less"></style>

四、URL(常用–>URL.createObjectURL())

1. 前言

一般使用window.URL.createObjectURL()方法比较多,主要用于获取文件对应的url。

注:加不加window.一般情况下没区别.

如果浏览器尚不支持URL()构造函数,则可以使用Window中的Window.URL (en-US)属性。

2. 构造函数

new URL()

2.1 构造函数的属性

属性描述
hash从#开始往后的所有信息
host域名+端口
hostname域名
href完整 URL
pathname端口之后,以 ‘/’ 起头,#之前的文件路径
search指示 URL 的参数字符串; 如果提供了任何参数,则此字符串包括所有参数,并以开头的“?”开头 字符。

3. 方法

方法描述
toString()返回包含整个 URL字符串,它是URL.href的同义词,尽管它不能用于修改值。
toJSON()返回包含整个 URL 的字符串。 它返回与href属性相同的字符串。

3.1 静态方法

方法描述
createObjectURL()返回一个字符串,包含一个唯一的 blob 链接(该链接协议为以 blob:,后跟唯一标识浏览器中的对象的掩码)方法参数:File对象和Blob对象
revokeObjectURL()销毁之前使用URL.createObjectURL()方法创建的 URL 实例。

4. 基础案例

4.1 基本demo打印url对象属性

<template>
  <div class="emqrcode">
    <a-upload :file-list="fileList" :before-upload="beforeUpload">
      <a-button> <a-icon type="upload" /> Select File </a-button>
    </a-upload>
    <div>------------------------------</div>
    <div ref="div"></div>
  </div>
</template>

<script>

export default {
  data () {
    return {
      fileList: []
    }
  },
  methods: {
    beforeUpload (file) {
      // 属性
      // 当前窗口的url:http://192.168.31.162:48079/historycity/#/test?pic=1
      const url = new URL(window.location.href) // window.location.href当前窗口的url
      console.log(url) // url对象
      console.log(url.hash) // #/test?pic=1
      console.log(url.host) // 192.168.31.162:48079
      console.log(url.hostname) // 192.168.31.162
      console.log(url.href) // http://192.168.31.162:48079/historycity/#/test?pic=1
      console.log(url.pathname) // /historycity/
      console.log(url.search)
      console.log(url.searchParams)
      console.log(url.toString()) // /historycity/
      console.log(url.toJSON()) // /historycity/
      return false
    }
  }
}
</script>

<style lang="less"></style>

4.2 实现图片预览

<template>
  <div class="emqrcode">
    <a-upload :file-list="fileList" :before-upload="beforeUpload">
      <a-button> <a-icon type="upload" /> Select File </a-button>
    </a-upload>
    <div>------------------------------</div>
    <div ref="div"></div>
  </div>
</template>

<script>

export default {
  data () {
    return {
      fileList: []
    }
  },
  methods: {
    beforeUpload (file) {
      this.fileList = [...this.fileList, file]
      const fileurl = window.URL.createObjectURL(file)
      console.log(fileurl) // blob:http://192.168.31.162:48079/b7af9406-fad8-4f05-8b7c-32c10a3fef58

      const img = new Image()
      img.src = fileurl
      this.$refs.div.appendChild(img)
      return false
    }
  }
}
</script>

<style lang="less"></style>

五、HTMLImageElement(new Image())

1. 前言

一般用new Image(width,height)生成<img/>标签,结合图片预览使用

2. 构造函数

new Image([width,height])创建了一个尚未被插入 DOM 树中的 HTMLImageElement 实例。

3. 属性

属性描述
alt表明图像的后备描述内容,会在图像无法加载时显示
src包含图像的完整的 URL,包含图像的基础 URL

4. 方法

方法描述
decode()返回一个当图片解码后可安全用于附加到 DOM 上时 resolves 的 Promise 对象。

5.基础案例

5.1结合图片预览使用

<template>
  <div class="emqrcode">
    <a-upload :file-list="fileList" :before-upload="beforeUpload">
      <a-button> <a-icon type="upload" /> Select File </a-button>
    </a-upload>
    <div>------------------------------</div>
    <div ref="div"></div>
  </div>
</template>

<script>

export default {
  data () {
    return {
      fileList: []
    }
  },
  methods: {
    beforeUpload (file) {
      this.fileList = [...this.fileList, file]
      const fileurl = window.URL.createObjectURL(file)
      console.log(fileurl) // blob:http://192.168.31.162:48079/b7af9406-fad8-4f05-8b7c-32c10a3fef58

      const img = new Image()
      img.src = fileurl
      this.$refs.div.appendChild(img)
      return false
    }
  }
}
</script>

<style lang="less"></style>

5.2 decode()的使用(使用场景:加载大图片时替换)

一个 decode() 的潜在用例:当在加载一个非常大的图片时(例如,一个在线相册),你可以在加载初期提供一个低分辨率的缩略图,之后通过实例化一个 HTMLImageElement 将该图像替换为一个全分辨率图像,设置其 source 为全分辨率图像 URL,使用 decode() 获取一旦全分辨率图像准备好被使用时 resolved 的 promise 对象。这时你可以使用当前可用的全分辨率图像替换之前的低分辨率图像。

<template>
  <div class="emqrcode">
    <a-upload :file-list="fileList" :before-upload="beforeUpload">
      <a-button> <a-icon type="upload" /> Select File </a-button>
    </a-upload>
    <div>------------------------------</div>
    <div ref="div"></div>
  </div>
</template>

<script>

export default {
  data () {
    return {
      fileList: []
    }
  },
  methods: {
    beforeUpload (file) {
      this.fileList = [...this.fileList, file]
      const fileurl = window.URL.createObjectURL(file)

      const img = new Image()
      img.src = fileurl
      img.decode()
        .then(() => {
          this.$refs.div.appendChild(img)
        })
        .catch((encodingError) => {
          // Do something with the error.
        })

      return false
    }
  }
}
</script>

<style lang="less"></style>
  • 7
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值