Blob介绍
定义
Blob 对象表示一个
不可变
、原始数据
的类文件对象
。它的数据可以按文本
或二进制
的格式进行读取,也可以转换成ReadableStream
来用于数据操作。 通常可以用于声音、视频等多媒体文件的存储;
构造
new Blob(blobParts, options);
blobParts
:数组类型,可以存放任意个ArrayBuffer
、ArrayBufferView
、Blob
或DOMString
(会编码为utf-8);
options
:可选,可以设置blob的type
和endings
;
- type:blob中数组元素的MIME类型,默认为
''
; - endings:包含行字符串
\n
的字符串如何被写入。默认值_transparent_
保留不变,_native_
会改为对应宿主操作系统文件系统的换行符。
DOMString 是一个UTF-16字符串。由于JavaScript已经使用了这样的字符串,所以DOMString直接映射到 一个String。
属性
type
:返回blob的MIME类型
size
:blob的数据大小(字节)
方法
返回一个新的 Blob 对象,包含了源 Blob 对象中指定范围内的数据。
Blob.slice([start[, end[, contentType]]])
// 返回一个能读取blob内容的 ReadableStream。
Blob.stream();
// 返回一个promise且包含blob所有内容的UTF-8格式的 USVString。
Blob.text()
// 返回一个promise且包含blob所有内容的二进制格式的 ArrayBuffer
Blob.arrayBuffer()
从Blob总提取数据
可以使用FileReader
对象
const reader = new FileReader();
reader.addEventListener('loaded', function() {
// reader.reasult 包含被转换为typedArray的Blob
});
reader.readAsArrayBuffer(blob);
可以使用Response
对象
const text = await (new Response(blob)).text()
File对象
定义
通常情况下, File 对象是来自用户在一个
<input>
元素上选择文件后返回的 FileList 对象,也可以是来自由拖放操作生成的 DataTransfer 对象,或者来自 HTMLCanvasElement 上的 mozGetAsFile() API
属性
name
:文件名
size
:文件大小
lastModified
:文件最后修改时间对应时间戳
type
:MIME类型
webkitRelativePath
:返回file
相关的path和URL
方法
slice
:继承了Blob的slice方法
demo
<input>
元素
<input type="file" id="fileUploader" multiple accept="image">
<script>
const el = document.getElementById('fileUploader');
el.onchange = (e) => {
const files = e.target.files;
console.log({ files }, files[0])
}
</script>
<div id="fileUploader"
ondrop="drop(e)"
ondragover="allowDrop(e)"
></div>
<script>
function drop(e) {
e.preventDefault();
const files = e.dataTransfer.files;
console.log({ files });
console.log(files instanceof FileList);
}
function allowDrop(e) {
e.preventDefault();
}
</script>
数据缓冲区
定义
数据缓冲区指的是内存中操作二进制数据的一片连续的存储区,相对于数组可以有效提高数据读取效率;
Buffer
Buffer
是Node
提供的对象,可以通过Buffer创建存储二进制数据的缓冲区用于整合前端媒体文件数据 等;
一个Buffer类似于一个整数数组,但它对应于V8堆内存之外的一块原始内存
;
ArrayBuffer
表示一段固定长度的连续的用于存储二进制数据的缓存区;对于高密度访问的数据(音视频数据等)读取效率更高,因为数据会提前写入到内存中;
属性——byteLength
,表示ArrayBuffer的大小
方法——slice(start, end)
,返回一个新的ArrayBuffer
ArrayBufferView
ArrayBuffer未提供任何直接读写内存的方法,而ArrayBufferView是建立在ArrayBuffer上的视图,提供了处理二进制数据的基本单元,可以读取ArrayBuffer的内容;
TypedArrays
和DataView
是ArrayBufferView的实例
FileReader
ileReader 对象允许 Web 应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据。
重要提示:FileReader 仅用于以安全的方式从用户(远程)系统读取文件内容 它不能用于从文件系统中按路径名简单地读取文件。要在 JavaScript 中按路径名读取文件,应使用标准 Ajax 解决方案进行服务器端文件读取,如果读取跨域,则使用 CORS 权限。
- readAsText(Blob):将Blob转化为文本字符串
- readAsArrayBuffer(Blob):将Blob转为ArrayBuffer格式数据
- readAsDataURL(): 将Blob转化为Base64格式的DataURL
以下demo通过FileReader展示上传的图片
<!DOCTYPE html>
<html class="no-js">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title></title>
<meta name="description" content="" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="" />
</head>
<body>
<input type="file" multiple id="myFile" />
<input type="file" multiple id="myFile2" />
<div id="previewer"></div>
<script type="text/javascript">
if (window.FileReader) {
var reader = new FileReader();
} else {
console.log('你的浏览器不支持读取文件');
}
var myFile = document.querySelector('#myFile');
myFile.onchange = function () {
var file = myFile.files[0];
reader.readAsDataURL(file);
reader.onload = function () {
var data = reader.result; //base64形式的文件内容
console.log('data: ', data);
const img = new Image();
img.src = data;
document.querySelector('#previewer').appendChild(img);
};
reader.onerror = function(){
console.log('读取失败');
console.log(reader.error);
}
};
// blobUrl(objectUrl)
var myFile2 = document.querySelector('#myFile2');
myFile2.onchange = function (event) {
const file = event.target.files[0];
const img = document.createElement('img');
img.src = window.URL.createObjectURL(file); // window.createObjectURL(file) || window.URL.createObjectURL(file) || window.webkitURL.createObjectURL(file)
document.querySelector('#previewer').appendChild(img);
}
</script>
</body>
</html>
以下demo通过FileReader读取一个text文本文件内容:
<!DOCTYPE html>
<html class="no-js">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title></title>
<meta name="description" content="" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="" />
</head>
<body>
<input type="file" multiple id="myFile" />
<input type="file" multiple id="myFile2" />
<input type="file" multiple id="textFile" />
<div id="previewer"></div>
<script type="text/javascript">
// reader.readerAsText(file)
const myFile3 = document.querySelector('#textFile');
const textReader = new FileReader();
myFile3.onchange = function (event) {
const file = event.target.files[0];
textReader.onload = function () {
const content = textReader.result;
console.log('text content: ', content);
}
textReader.readAsText(file);
}
</script>
</body>
</html>
BlobURL
**BlobURL(ObjectURL)**是一种伪协议,只能由浏览器在内部生成,我们知道script/img/video/iframe等标签的src属性和background的url可以通过url和base64来显示,我们同样可以把blob或者file转换为url生成BlobURL来展示图像,BlobURL允许Blob和File对象用作图像,下载二进制数据链接等的URL源。
图像展示
具体代码见上面demo
文档下载
<!DOCTYPE html>
<html class="no-js">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title></title>
<meta name="description" content="" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="" />
</head>
<body>
<input type="file" multiple id="myFile" />
<input type="file" multiple id="myFile2" />
<input type="file" multiple id="textFile" />
<button onclick="download()">下载</button>
<div id="previewer"></div>
<script type="text/javascript">
if (window.FileReader) {
var reader = new FileReader();
} else {
console.log('你的浏览器不支持读取文件');
}
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;
};
var myFile = document.querySelector('#myFile');
myFile.onchange = function () {
var file = myFile.files[0];
reader.readAsDataURL(file);
reader.onload = function () {
var data = reader.result; //base64形式的文件内容
console.log('data: ', data);
const img = new Image();
img.src = data;
document.querySelector('#previewer').appendChild(img);
};
reader.onerror = function () {
console.log('读取失败');
console.log(reader.error);
}
};
// blobUrl(objectUrl)
var myFile2 = document.querySelector('#myFile2');
myFile2.onchange = function (event) {
const file = event.target.files[0];
const img = document.createElement('img');
img.src = window.URL.createObjectURL(file); // window.createObjectURL(file) || window.URL.createObjectURL(file) || window.webkitURL.createObjectURL(file)
document.querySelector('#previewer').appendChild(img);
}
// reader.readerAsText(file)
const myFile3 = document.querySelector('#textFile');
const textReader = new FileReader();
myFile3.onchange = function (event) {
const file = event.target.files[0];
textReader.onload = function () {
const content = textReader.result;
console.log('text content: ', content);
}
textReader.readAsText(file);
}
// file download
function download() {
const fileName = 'download.txt';
const myBlob = new Blob(['BlobURL download text file'], { type: 'text/plain' });
downloadFn(fileName, myBlob);
}
function downloadFn(fileName, blob) {
const link = document.createElement('a');
link.href = getObjectURL(blob);
link.download = fileName;
link.click();
link.remove();
URL.revokeObjectURL(link.href); // 不再使用的BlobUrl后续会自动清除(关闭浏览器也会自动清除),但是最好使用URL.revokeObjectURL(url)手动清除它们
}
</script>
</body>
</html>
dataURL
dataURL允许内容的创建者将较小的文件嵌入到文档中。与常规的URL使用场合类似
用法:
data:[<mediatype>][;base64],data
- data: 固定前缀
- mediatype: 表明数据类型,是一个_MIME_类型字符串,如image/jpeg表示一个JPEG图片文件。如果省略,默认值为_text/plain;charset=US-ASCII_。
- base64: 标志位(如果是文本,则可选)
- data: 数据本身
如何获取dataURL
Javascript中有两个函数负责编码和解码base64字符串,分别是atob和btoa。两者都只针对Data URL中的data进行处理。
dataURL使用
- 当图片的体积太小,占用一个HTTP会话不是很值得时。
- 当访问外部资源很麻烦或受限时
- DataUrl不会被浏览器缓存,但是小部分会通过css缓存,在下面例子中,DataUrl的使用是完全符合场
- 作为下载连接使用
dataURL vs BlobURL
数据格式转换
应用场景
图像灰度化
这里主要用到canvas和imageData的转换
<!DOCTYPE html>
<html class="no-js">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title></title>
<meta name="description" content="" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="" />
<style>
.imgPreviewer {
display: flex;
}
</style>
</head>
<body>
<input type="file" multiple id="myFile" />
<input type="file" multiple id="myFile2" />
<input type="file" multiple id="textFile" />
<button onclick="download()">下载</button>
<input type="file" id="grayImage" />
<div id="previewer"></div>
<div class="imgPreviewer">
<canvas id="original"></canvas>
<canvas id="gray"></canvas>
</div>
<script type="text/javascript">
if (window.FileReader) {
var reader = new FileReader();
} else {
console.log('你的浏览器不支持读取文件');
}
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;
};
var myFile = document.querySelector('#myFile');
myFile.onchange = function () {
var file = myFile.files[0];
reader.readAsDataURL(file);
reader.onload = function () {
var data = reader.result; //base64形式的文件内容
console.log('data: ', data);
const img = new Image();
img.src = data;
document.querySelector('#previewer').appendChild(img);
};
reader.onerror = function () {
console.log('读取失败');
console.log(reader.error);
}
};
// blobUrl(objectUrl)
var myFile2 = document.querySelector('#myFile2');
myFile2.onchange = function (event) {
const file = event.target.files[0];
const img = document.createElement('img');
img.src = window.URL.createObjectURL(file); // window.createObjectURL(file) || window.URL.createObjectURL(file) || window.webkitURL.createObjectURL(file)
document.querySelector('#previewer').appendChild(img);
}
// reader.readerAsText(file)
const myFile3 = document.querySelector('#textFile');
const textReader = new FileReader();
myFile3.onchange = function (event) {
const file = event.target.files[0];
textReader.onload = function () {
const content = textReader.result;
console.log('text content: ', content);
}
textReader.readAsText(file);
}
// file download
function download() {
const fileName = 'download.txt';
const myBlob = new Blob(['BlobURL download text file'], { type: 'text/plain' });
downloadFn(fileName, myBlob);
}
function downloadFn(fileName, blob) {
const link = document.createElement('a');
link.href = getObjectURL(blob);
link.download = fileName;
link.click();
link.remove();
URL.revokeObjectURL(link.href); // 不再使用的BlobUrl后续会自动清除(关闭浏览器也会自动清除),但是最好使用URL.revokeObjectURL(url)手动清除它们
}
// 图像灰度化
const colorfulImageReader = document.querySelector('#grayImage');
const imgReader = new FileReader();
colorfulImageReader.onchange = (event) => {
const file = event.target.files[0];
imgReader.readAsDataURL(file);
imgReader.onload = () => {
const result = imgReader.result;
const img = document.createElement('img');
img.src = result;
img.width = 300;
img.height = 440;
document.querySelector('#previewer').appendChild(img);
console.log('images: ', img, img.width, img.height)
img.onload = () => {
const canvas = document.getElementById('original');
const context = canvas.getContext('2d');
canvas.width = img.width;
canvas.height = img.height;
context.drawImage(img, 0, 0, img.width, img.height);
var imageData, data, i, len, average, red, green, blue;
imgData = context.getImageData(0, 0, img.width, img.height);
data = imgData.data;
for (i = 0, len = data.length; i < len; i += 4) {
red = data[i];
green = data[i + 1];
blue = data[i + 2];
// alpha = data[i + 3];
average = Math.floor((red + green + blue) / 3);
data[i] = average;
data[i + 1] = average;
data[i + 2] = average;
}
imgData.data = data;
const myCanvas = document.getElementById('gray');
myCanvas.width = img.width;
myCanvas.height = img.height;
const myContext = myCanvas.getContext('2d');
myContext.putImageData(imgData, 0, 0, 0, 0, img.width, img.height);
}
}
}
</script>
</body>
</html>
图片压缩
A Number between 0 and 1 indicating the image quality to be used when creating images using file formats that support lossy compression (such as image/jpeg or image/webp). A user agent will use its default quality value if this option is not specified, or if the number is outside the allowed range.
toDataURL(type, encoderOptions)第二个参数可以用于控制图片质量,可以用此参数实现图片压缩
// compress.js
const MAX_WIDTH = 800; // 图片最大宽度
function compress(base64, quality, mimeType) {
let canvas = document.createElement('canvas');
let img = document.createElement('img');
img.crossOrigin = 'anonymous';
return new Promise((resolve, reject) => {
img.src = base64;
img.onload = () => {
let targetWidth, targetHeight;
if (img.width > MAX_WIDTH) {
targetWidth = MAX_WIDTH;
targetHeight = (img.height * MAX_WIDTH) / img.width;
} else {
targetWidth = img.width;
targetHeight = img.height;
}
canvas.width = targetWidth;
canvas.height = targetHeight;
let ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, targetWidth, targetHeight); // 清除画布
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
// 通过toDataURL压缩后的base64
let imageData = canvas.toDataURL(mimeType, quality / 100);
resolve(imageData);
};
});
}
<body>
<input type="file" accept="image/*" onchange="loadFile(event)" />
<script src="./compress.js"></script>
<script>
function dataUrlToBlob(base64) {
var arr = base64.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 });
}
function uploadFile(url, blob) {
let formData = new FormData();
let request = new XMLHttpRequest();
// 封装到FormData中进行文件的上传
formData.append('image', blob);
request.open('POST', url, true);
request.send(formData);
}
const loadFile = function (event) {
const reader = new FileReader();
reader.onload = async function () {
let compressedDataURL = await compress(reader.result, 90, 'image/jpeg');
// 压缩后将base64转为Blob 对象减少传输数据量
let compressedImageBlob = dataUrlToBlob(compressedDataURL);
uploadFile('https://httpbin.org/post', compressedImageBlob);
};
// 获取用户选取的图片文件,通过FileReader转化成base64
reader.readAsDataURL(event.target.files[0]);
};
</script>
</body>