文件二进制
Blob
专门用于支持文件操作的二进制对象,第一个参数是typedArray二维数组,第二个参数是 MIME 类型
const blob = new Blob([u8Arr], { type: "application/pdf"})
const blob = new Blob([u8Arr], { type: "application/pdf"})
File
文件(File
)对象提供有关文件的信息,并允许网页中的 JavaScript 访问其内容
通常情况下, File
对象是来自用户在一个input元素上选择文件后返回的 FileList
对象,也可以是来自由拖放操作生成的 DataTransfer
对象,或者来自 HTMLCanvasElement
上的 mozGetAsFile
API
Blob 是最原始的文件对象,File 是基于 Blob 改造的,File继承了所有Blob的属性方法,所以File对象可以看作一种特殊的Blob对象
FileReader
, URL.createObjectURL()
, createImageBitmap()
(en-US), 及 XMLHttpRequest.send()
都能处理 Blob
和 File
示例-浏览器预览本地pdf文件
<template>
<input type="file" @change="update" />
</template>
<script lang="ts" setup>
function update(e: any) {
const file = e.target.files[0]
const reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = res => {
const base64 = res.target!.result as string
const bstr = atob(base64.substring(base64.indexOf(",") + 1))
let n = bstr.length
const u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
const blob = new Blob([u8arr], { type: "application/pdf" })
const a = document.createElement("a")
const url = URL.createObjectURL(blob)
a.href = url
// 下载的话加一句
// a.download = "name"
a.click()
URL.revokeObjectURL(url)
}
}
</script>
<template>
<input type="file" @change="update" />
</template>
<script lang="ts" setup>
function update(e: any) {
const file = e.target.files[0]
const reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = res => {
const base64 = res.target!.result as string
const bstr = atob(base64.substring(base64.indexOf(",") + 1))
let n = bstr.length
const u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
const blob = new Blob([u8arr], { type: "application/pdf" })
const a = document.createElement("a")
const url = URL.createObjectURL(blob)
a.href = url
// 下载的话加一句
// a.download = "name"
a.click()
URL.revokeObjectURL(url)
}
}
</script>
FileReader
FileReader
对象允许web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File
或 Blob
对象指定要读取的文件或数据
其中File
对象可以是来自用户在一个<input>元素上选择文件后返回的FileList
对象,也可以来自拖放操作生成的 DataTransfer
对象,还可以是来自在一个HTMLCanvasElement
上执行mozGetAsFile()
方法后的返回结果
构造函数
创建FileReader对象
let reader = new FileReader()
let reader = new FileReader()
APi
方法名 | 参数 | 描述 |
---|---|---|
readAsBinaryString | file | 将文件读取为二进制编码 |
readAsText | file,[encoding] | 将文件读取为文本 |
readAsDataURL | file | 将文件读取为DataURL,base64 |
abort | (none) | 终端读取操作 |
事件触发
事件 | 触发时机 |
---|---|
onabort | 当读取操作被中止时调用 |
onerror | 当读取操作发生错误时调用 |
onload | 当读取操作成功完成时调用 |
onloadend | 当读取操作完成时调用,不管是成功还是失败.该处理程序在onload 或者onerror 之后调用 |
onloadstart | 当读取操作将要开始之前调用 |
onprogress | 在读取数据过程中周期性调用 |
示例-读取txt
<template>
<input type="file" @change="readTxt" />
<p>{{ txt }}</p>
</template>
<script lang="ts" setup>
const txt = ref("")
function readTxt(e: any) {
const reader = new FileReader()
reader.readAsText(e.target.files[0], "UTF-8")
reader.onload = e => {
txt.value = e.target?.result as string
}
}
</script>
<template>
<input type="file" @change="readTxt" />
<p>{{ txt }}</p>
</template>
<script lang="ts" setup>
const txt = ref("")
function readTxt(e: any) {
const reader = new FileReader()
reader.readAsText(e.target.files[0], "UTF-8")
reader.onload = e => {
txt.value = e.target?.result as string
}
}
</script>
示例-选择图片浏览器中预览
<template>
<div>
<input type="file" @change="readImg" />
<img :src="imgSrc" />
</div>
</template>
<script>
export default {
data() {
return {
imgSrc: ""
}
},
methods: {
readImg(e) {
const reader = new FileReader()
const file = e.target.files[0]
reader.readAsDataURL(file)
reader.onload = e => {
this.imgSrc = e.target.result
}
}
}
}
</script>
<template>
<div>
<input type="file" @change="readImg" />
<img :src="imgSrc" />
</div>
</template>
<script>
export default {
data() {
return {
imgSrc: ""
}
},
methods: {
readImg(e) {
const reader = new FileReader()
const file = e.target.files[0]
reader.readAsDataURL(file)
reader.onload = e => {
this.imgSrc = e.target.result
}
}
}
}
</script>
示例-选择pdf浏览器中预览
<template>
<input type="file" @change="readImg" />
</template>
<script lang="ts" setup>
function readImg(e: any) {
const reader = new FileReader()
const base64 = e.target.files[0]
reader.readAsDataURL(base64)
reader.onload = e => {
blobToFile(e.target?.result as string)
}
}
const base64ToBlob = function (base64: string) {
let bstr = atob(base64.split(",")[1])
let l = bstr.length
let u8Arr = new Uint8Array(l)
while (l--) {
u8Arr[l] = bstr.charCodeAt(l)
}
return new Blob([u8Arr], {
type: "application/pdf"
})
}
// blob转file
const blobToFile = function (base64: string) {
const blob = base64ToBlob(base64)
let fileURL = URL.createObjectURL(blob)
window.open(fileURL)
}
</script>
<template>
<input type="file" @change="readImg" />
</template>
<script lang="ts" setup>
function readImg(e: any) {
const reader = new FileReader()
const base64 = e.target.files[0]
reader.readAsDataURL(base64)
reader.onload = e => {
blobToFile(e.target?.result as string)
}
}
const base64ToBlob = function (base64: string) {
let bstr = atob(base64.split(",")[1])
let l = bstr.length
let u8Arr = new Uint8Array(l)
while (l--) {
u8Arr[l] = bstr.charCodeAt(l)
}
return new Blob([u8Arr], {
type: "application/pdf"
})
}
// blob转file
const blobToFile = function (base64: string) {
const blob = base64ToBlob(base64)
let fileURL = URL.createObjectURL(blob)
window.open(fileURL)
}
</script>
Base64
Base64
是一组相似的二进制到文本(binary-to-text)的编码规则,使得二进制数据在解释成 radix-64 的表现形式后能够用 ASCII 字符串的格式表示出来。Base64
这个词出自一种 MIME 数据传输编码
Base64编码普遍应用于需要通过被设计为处理文本数据的媒介上储存和传输二进制数据而需要编码该二进制数据的场景。这样是为了保证数据的完整并且不用在传输过程中修改这些数据。Base64 也被一些应用(包括使用 MIME 的电子邮件)和在 XML (en-US) 中储存复杂数据时使用。
在 JavaScript 中,有两个函数被分别用来处理解码和编码 base64 字符串:
atob
函数能够解码通过base-64编码的字符串数据。相反地,btoa
函数能够从二进制数据字符串创建一个base64编码的ASCII字符串
atob()
和 btoa()
均使用字符串
可以直接作为img图片的src路径
blob转base64
const reader = new FileReader()
reader.readAsDataURL(blob)
reader.onload = e => {
console.log(e.target.result)
}
const reader = new FileReader()
reader.readAsDataURL(blob)
reader.onload = e => {
console.log(e.target.result)
}
ArrayBuffer
先来了解一个专业名词,视图(view)
,指的是对同一段内存,采取不同的解读方式,所以视图的作用就是以指定格式解读二进制数据,如:
// 创建一个8字节的ArrayBuffer
const b = new ArrayBuffer(8)
// 创建一个指向b的Int32视图,开始于字节0,直到缓冲区的末尾
const v1 = new Int32Array(b)
// 创建一个指向b的Uint8视图,开始于字节2,直到缓冲区的末尾
const v2 = new Uint8Array(b, 2)
// 创建一个指向b的Int16视图,开始于字节2,长度为2
const v3 = new Int16Array(b, 2, 2)
// 创建一个8字节的ArrayBuffer
const b = new ArrayBuffer(8)
// 创建一个指向b的Int32视图,开始于字节0,直到缓冲区的末尾
const v1 = new Int32Array(b)
// 创建一个指向b的Uint8视图,开始于字节2,直到缓冲区的末尾
const v2 = new Uint8Array(b, 2)
// 创建一个指向b的Int16视图,开始于字节2,长度为2
const v3 = new Int16Array(b, 2, 2)
ArrayBuffer
对象是固定长度的二进制数据缓冲区,即一段内存,它不能直接读写,只能通过视图(浏览器端TypedArray
视图和DataView
视图 , nodejs中特有视图Buffer
)来读写
ArrayBuffer对象作为内存区域,可以存放多种类型的数据
ArrayBuffer
有两种视图,一种是TypedArray
视图,另一种是DataView
视图。前者的数组成员都是同一个数据类型,后者的数组成员可以是不同的数据类型
ArrayBuffer
也是一个构造函数,可以分配一段可以存放数据的连续内存区域
const buf = new ArrayBuffer(32)
// Uint8Array属于TypedArray视图
const view = new Uint8Array(32)
const buf = new ArrayBuffer(32)
// Uint8Array属于TypedArray视图
const view = new Uint8Array(32)
- ArrayBuffer存放0和1组成的二进制数据
- 数组放在堆中,ArrayBuffer则把数据放在栈中,所以取数据时更快
- ArrayBuffer初始化后固定大小,数组则可以自由增减
TypedArray
目前,TypedArray
视图一共包括 9 种类型,每一种类型都是一种构造函数
Int8Array
:8 位有符号整数,长度 1 个字节Uint8Array
:8 位无符号整数,长度 1 个字节Uint8ClampedArray
:8 位无符号整数,长度 1 个字节,溢出处理不同Int16Array
:16 位有符号整数,长度 2 个字节Uint16Array
:16 位无符号整数,长度 2 个字节Int32Array
:32 位有符号整数,长度 4 个字节Uint32Array
:32 位无符号整数,长度 4 个字节Float32Array
:32 位浮点数,长度 4 个字节Float64Array
:64 位浮点数,长度 8 个字节
这 9 个构造函数生成的数组,统称为TypedArray
视图。它们很像普通数组,都有length
属性,都能用方括号运算符([]
)获取单个元素,所有数组的方法,在它们上面都能使用。普通数组与 TypedArray 数组的差异主要在以下方面。
- TypedArray 数组的所有成员,都是同一种类型
- TypedArray 数组的成员是连续的,不会有空位
- TypedArray 数组成员的默认值为 0。比如,
new Array(10)
返回一个普通数组,里面没有任何成员,只是 10 个空位;new Uint8Array(10)
返回一个 TypedArray 数组,里面 10 个成员都是 0 - TypedArray 数组只是一层视图,本身不储存数据,它的数据都储存在底层的
ArrayBuffer
对象之中,要获取底层对象必须使用buffer
属性
// 创建一个8字节的ArrayBuffer
const b = new ArrayBuffer(8)
// 创建一个指向b的Int32视图,开始于字节0,直到缓冲区的末尾
const v1 = new Int32Array(b)
// 创建一个指向b的Uint8视图,开始于字节2,直到缓冲区的末尾
const v2 = new Uint8Array(b, 2)
// 创建一个指向b的Int16视图,开始于字节2,长度为2
const v3 = new Int16Array(b, 2, 2)
// 创建一个8字节的ArrayBuffer
const b = new ArrayBuffer(8)
// 创建一个指向b的Int32视图,开始于字节0,直到缓冲区的末尾
const v1 = new Int32Array(b)
// 创建一个指向b的Uint8视图,开始于字节2,直到缓冲区的末尾
const v2 = new Uint8Array(b, 2)
// 创建一个指向b的Int16视图,开始于字节2,长度为2
const v3 = new Int16Array(b, 2, 2)
- 第一个参数(必需):视图对应的
ArrayBuffer
对象 - 第二个参数(可选):视图开始的字节序号,默认从 0 开始
- 第三个参数(可选):视图包含的数据个数,默认直到本段内存区域结束
Uint8Array
TypedArray视图
的九种类型之一
Uint8Array
数组类型表示一个8位无符号整型数组,创建时内容被初始化为0。创建完后,可以以对象的方式或使用数组下标索引的方式引用数组中的元素
const uint8 = new Uint8Array(2)
uint8[0] = 42
console.log(uint8[0]) // 42
console.log(uint8.length) // 2
const uint8 = new Uint8Array(2)
uint8[0] = 42
console.log(uint8[0]) // 42
console.log(uint8.length) // 2
普通数组转Uint8Array
const arr = [1,2,3]
const uint8 = new Uint8Array(arr)
const arr = [1,2,3]
const uint8 = new Uint8Array(arr)
Buffer
Buffer
是Node.JS中特有的一种视图(浏览器没有),与TypedArray
视图和DataView
视图并驾齐驱
let buffer = new Buffer(arraybuffer)
let buffer = new Buffer(arraybuffer)
charCodeAt
返回字符串第一个字符的 Unicode 编码(H 的 Unicode 值)
const str = "HELLO WORLD"
const n = str.charCodeAt(0)
const str = "HELLO WORLD"
const n = str.charCodeAt(0)
浏览器使用jspdf导出pdf
<template>
<button @click="exportPDF">导出pdf</button>
</template>
<script lang="ts" setup>
import jsPDF from "jspdf"
function exportPDF() {
const doc = new jsPDF()
doc.text("Hello world!", 10, 10)
let u8Arr = new Uint8Array(doc.output("arraybuffer"))
const blob = new Blob([u8Arr], {
type: "application/pdf"
})
let fileURL = URL.createObjectURL(blob)
window.open(fileURL)
}
</script>
<template>
<button @click="exportPDF">导出pdf</button>
</template>
<script lang="ts" setup>
import jsPDF from "jspdf"
function exportPDF() {
const doc = new jsPDF()
doc.text("Hello world!", 10, 10)
let u8Arr = new Uint8Array(doc.output("arraybuffer"))
const blob = new Blob([u8Arr], {
type: "application/pdf"
})
let fileURL = URL.createObjectURL(blob)
window.open(fileURL)
}
</script>
node中使用jspdf导出pdf
使用nodejs特有视图Buffer读写arraybuffer
const { jsPDF } = require("jspdf")
const fs = require("fs")
const doc = new jsPDF()
doc.text("Hello world!", 10, 10)
let rawdata = doc.output("arraybuffer")
let buffer = new Buffer(rawdata)
fs.writeFile("1.pdf", buffer, function (e) {
if (e) throw e
console.log("文件已被保存")
})
const { jsPDF } = require("jspdf")
const fs = require("fs")
const doc = new jsPDF()
doc.text("Hello world!", 10, 10)
let rawdata = doc.output("arraybuffer")
let buffer = new Buffer(rawdata)
fs.writeFile("1.pdf", buffer, function (e) {
if (e) throw e
console.log("文件已被保存")
})
使用TypedArray(Uint8Array)读写arraybuffer
const { jsPDF } = require("jspdf")
const fs = require("fs")
const doc = new jsPDF()
doc.text("Hello world!", 10, 10)
let rawdata = doc.output("arraybuffer")
fs.writeFile("1.pdf", new Uint8Array(rawdata), function (e) {
if (e) throw e
console.log("文件已被保存")
})
const { jsPDF } = require("jspdf")
const fs = require("fs")
const doc = new jsPDF()
doc.text("Hello world!", 10, 10)
let rawdata = doc.output("arraybuffer")
fs.writeFile("1.pdf", new Uint8Array(rawdata), function (e) {
if (e) throw e
console.log("文件已被保存")
})
粘贴图片
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<style>
body,
html {
text-align: center;
}
#editDiv {
width: 1000px;
display: inline-block;
height: 800px;
background: #fff;
border-radius: 10px;
line-height: 20px;
padding: 10px;
font-size: 14px;
color: #666;
resize: none;
outline: none;
overflow-y: scroll;
}
#editDiv {
border: 1px solid #333;
border-color: rgba(169, 169, 169, 1);
text-align: left;
}
</style>
</head>
<body>
<div id="editDiv" contenteditable="true"></div>
</body>
<script src="js/jquery.min.js"></script>
<script>
document.querySelector("#editDiv").addEventListener(
"paste",
function (e) {
var cbd = e.clipboardData
var ua = window.navigator.userAgent
// 如果是 Safari 直接 return
if (!(e.clipboardData && e.clipboardData.items)) {
return
}
// Mac平台下Chrome49版本以下 复制Finder中的文件的Bug Hack掉
if (
cbd.items &&
cbd.items.length === 2 &&
cbd.items[0].kind === "string" &&
cbd.items[1].kind === "file" &&
cbd.types &&
cbd.types.length === 2 &&
cbd.types[0] === "text/plain" &&
cbd.types[1] === "Files" &&
ua.match(/Macintosh/i) &&
Number(ua.match(/Chrome\/(\d{2})/i)[1]) < 49
) {
return
}
for (var i = 0; i < cbd.items.length; i++) {
var item = cbd.items[i]
if (item.kind == "file") {
var blob = item.getAsFile()
if (blob.size === 0) {
return
}
/*-----------------------与后台进行交互 end-----------------------*/
/*-----------------------不与后台进行交互 直接预览start-----------------------*/
var reader = new FileReader()
var imgs = new Image()
imgs.file = blob
reader.onload = (function (aImg) {
return function (e) {
aImg.src = e.target.result
}
})(imgs)
reader.readAsDataURL(blob)
document.querySelector("#editDiv").appendChild(imgs)
/*-----------------------不与后台进行交互 直接预览end-----------------------*/
}
}
},
false
)
</script>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<style>
body,
html {
text-align: center;
}
#editDiv {
width: 1000px;
display: inline-block;
height: 800px;
background: #fff;
border-radius: 10px;
line-height: 20px;
padding: 10px;
font-size: 14px;
color: #666;
resize: none;
outline: none;
overflow-y: scroll;
}
#editDiv {
border: 1px solid #333;
border-color: rgba(169, 169, 169, 1);
text-align: left;
}
</style>
</head>
<body>
<div id="editDiv" contenteditable="true"></div>
</body>
<script src="js/jquery.min.js"></script>
<script>
document.querySelector("#editDiv").addEventListener(
"paste",
function (e) {
var cbd = e.clipboardData
var ua = window.navigator.userAgent
// 如果是 Safari 直接 return
if (!(e.clipboardData && e.clipboardData.items)) {
return
}
// Mac平台下Chrome49版本以下 复制Finder中的文件的Bug Hack掉
if (
cbd.items &&
cbd.items.length === 2 &&
cbd.items[0].kind === "string" &&
cbd.items[1].kind === "file" &&
cbd.types &&
cbd.types.length === 2 &&
cbd.types[0] === "text/plain" &&
cbd.types[1] === "Files" &&
ua.match(/Macintosh/i) &&
Number(ua.match(/Chrome\/(\d{2})/i)[1]) < 49
) {
return
}
for (var i = 0; i < cbd.items.length; i++) {
var item = cbd.items[i]
if (item.kind == "file") {
var blob = item.getAsFile()
if (blob.size === 0) {
return
}
/*-----------------------与后台进行交互 end-----------------------*/
/*-----------------------不与后台进行交互 直接预览start-----------------------*/
var reader = new FileReader()
var imgs = new Image()
imgs.file = blob
reader.onload = (function (aImg) {
return function (e) {
aImg.src = e.target.result
}
})(imgs)
reader.readAsDataURL(blob)
document.querySelector("#editDiv").appendChild(imgs)
/*-----------------------不与后台进行交互 直接预览end-----------------------*/
}
}
},
false
)
</script>
</html>