Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FileReader、Blob、FormData、atob、btoa #44

Open
kekobin opened this issue Sep 26, 2019 · 0 comments
Open

FileReader、Blob、FormData、atob、btoa #44

kekobin opened this issue Sep 26, 2019 · 0 comments

Comments

@kekobin
Copy link
Owner

kekobin commented Sep 26, 2019

FileReader

FileReader接口提供了读取文件的方法和包含读取结果的事件模型。

方法

image

readAsBinaryString 通过用于传送到后端作为文件内容直接存储,一般还需要经过Array Buffer的实例存起来再传输。
Data URL是一种将小文件直接嵌入文档的方案。这里的小文件通常是指图像与 html 等格式的文件。

事件

image

FileReader的读取是个异步的过程,读取结果保存在 result 属性中:

fr.onload = function() {
    this.result;
};

实例一:上传文件并读取为dataURI


<input type="file" name="file" οnchange="showPreview(this)" />
<img id="portrait" src="" width="70" height="75">

<script type="text/javascript">
	function showPreview(source) {
		var file = source.files[0];
		if(window.FileReader) {
			var fr = new FileReader();
			fr.onloadend = function(e) {
				document.getElementById("portrait").src = e.target.result;
			};
			fr.readAsDataURL(file);
		}
	}
</script>

实例二:拖拽图片进行预览

拖拽图片到一个容器,然后另一个容器能同时展示出改图:

var box = document.getElementById("box");    
var box2 = document.getElementById("box2");
     
box.οndragοver = function(e) {  
	e = e || window.event
	e.preventDefault();

	this.style.background = "#ddd"      
}

        
box.οndrοp = function(e) {  
	e.preventDefault();
       
	this.style.background = "#fff"
     
	var files = e.dataTransfer.files;
      
	for (var i = 0; i < files.length; i++) {
		if (files[i].type.indexOf("image") != -1) {        
			var fReader = new FileReader();             
			fReader.readAsDataURL(files[i]);
       
			fReader.οnlοad = function()  {            
				var img = document.createElement("img");
         
				img.src = this.result;           
				box2.appendChild(img)             
			}           
		} else {  
			alert("无法获取信息,您拖入的不是图片文件")         
		}          
	}      
}

Blob

在一般的Web开发中,很少会用到Blob,但Blob可以满足一些场景下的特殊需求。Blob,Binary Large Object的缩写,代表二进制类型的大对象。Blob的概念在一些数据库中有使用到,例如,MYSQL中的BLOB类型就表示二进制数据的容器。在Web中,Blob类型的对象表示不可变的类似文件对象的原始数据,通俗点说,就是Blob对象是二进制数据,但它是类似文件对象的二进制数据,因此可以像操作File对象一样操作Blob对象,实际上,File继承自Blob

一个 Blob ( Binary Large Object ) 对象表示一个不可变的, 原始数据的类似文件对象。Blob表示的数据不一定是一个JavaScript原生格式。 File 接口基于Blob,继承 Blob 功能并将其扩展为支持用户系统上的文件。简单地说 Blob 可以理解为 Web 中的二进制文件。 而 File 是基于 Blob 实现的一个类,新增了关于文件有关的一些信息。

创建

Blob(blobParts[, options])      

blobParts:数组类型,数组中的每一项连接起来构成Blob对象的数据,数组中的每项元素可以是ArrayBuffer, ArrayBufferView, Blob, DOMString 。
options:可选项,字典格式类型,可以指定如下两个属性:

  • type,默认值为 "",它代表了将会被放入到blob中的数组内容的MIME类型。
  • endings,默认值为"transparent",用于指定包含行结束符\n的字符串如何被写入。 它是以下两个值中的一个: "native",表示行结束符会被更改为适合宿主操作系统文件系统的换行符; "transparent",表示会保持blob中保存的结束符不变。
new Blob(['a']) // 输出:Blob {size: 1, type: ""}       
new Blob([JSON.stringify({ "name": "abc" })]);  // 输出:Blob {size: 14, type: ""}

size代表Blob 对象中所包含数据的字节数。

slice方法

slice([start[, end[, contentType]]])

返回一个新的 Blob对象,包含了源 Blob对象中指定范围内的数据

使用场景

分片上传

因为File继承自Blob,因此我们可以调用slice方法对大文件进行分片长传:

function uploadFile(file) {
	var chunkSize = 1024 * 1024; // 每片1M大小
	var totalSize = file.size;
	var chunkQuantity = Math.ceil(totalSize / chunkSize); //分片总数
	var offset = 0; // 偏移量

	var reader = new FileReader();
	reader.onload = function(e) {
		var xhr = new XMLHttpRequest();
		xhr.open("POST", "http://xxxx/upload?fileName=" + file.name);
		xhr.overrideMimeType("application/octet-stream");

		xhr.onreadystatechange = function() {
			if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
				++offset;
				if (offset === chunkQuantity) {
					alert("上传完成");
				} else if (offset === chunkQuantity - 1) {
					blob = file.slice(offset * chunkSize, totalSize); // 上传最后一片
					reader.readAsBinaryString(blob);
				} else {
					blob = file.slice(offset * chunkSize, (offset + 1) * chunkSize);
					reader.readAsBinaryString(blob);
				}
			} else {
				alert("上传出错");
			}
		}

		if (xhr.sendAsBinary) {
			xhr.sendAsBinary(e.target.result); // e.target.result是此次读取的分片二进制数据
		} else {
			xhr.send(e.target.result);
		}
	}
	var blob = file.slice(0, chunkSize);
	reader.readAsBinaryString(blob);
}

Blob URL

Blob URL是blob协议的URL,它的格式如下:

blob:http://XXX

Blob URL可以通过URL.createObjectURL(blob)创建。在绝大部分场景下,我们可以像使用Http协议的URL一样,使用Blob URL。常见的场景有:作为文件的下载地址和作为图片资源地址。

文件下载地址

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Blob Test</title>
    <script>
        function createDownloadFile() {
            var content = "Blob Data";
            var blob = new Blob([content]);
            var link = document.getElementsByTagName("a")[0];
            link.download = "file";
            window.URL = window.URL || window.webkitURL; 
            link.href = URL.createObjectURL(blob);
        }
        window.onload = createDownloadFile;
    </script>
</head>

<body>
    <a>下载</a>
</body>

</html>

点击下载按钮,浏览器将会下载一个名为file的文件,文件的内容是:Blob Data。通过Blob对象,我们在前端代码中就可以动态生成文件,提供给浏览器下载。

图片资源地址

为图片文件创建一个Blob URL,赋值给标签:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Blob Test</title>
    <script>
        function handleFile(e) {
            var file = e.files[0];
            var blob = URL.createObjectURL(file);
            var img = document.getElementsByTagName("img")[0];
            img.src = blob;
            img.onload = function(e) {
                URL.revokeObjectURL(this.src);  // 释放createObjectURL创建的对象##
            }
        }
    </script>
</head>

<body>
    <input type="file" accept="image/*" onchange="handleFile(this)" />
    <br/>
    <img style="width:200px;height:200px">
</body>

</html>

nput中选择的图片会在里显示出来。

该功能等同于使用Data URL加载图片资源:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Blob Test</title>
    <script>
        function handleFile(e) {
            var file = e.files[0];
            var fileReader = new FileReader();
            var img = document.getElementsByTagName("img")[0];
            fileReader.onload = function(e) {
                img.src = e.target.result;
            }
            fileReader.readAsDataURL(file);
        }
    </script>
</head>

<body>
    <input type="file" accept="image/*" onchange="handleFile(this)" />
    <br/>
    <img style="width:200px;height:200px">
</body>

</html>

FormData(用于模拟表单)

上传文件的格式一般是

  • base64格式
  • new FormData (ios,andorid只支持FormData 却不支持base64)

传统的form表单上传

<form id= "uploadForm" action= "http://xxx/file/upload" method= "post" enctype ="multipart/form-data">    
     <h1 >测试通过Rest接口上传文件 </h1>    
     <p >指定文件名: <input type ="text" name="filename" /></p>    
     <p >上传文件: <input type ="file" name="file" /></p>       
     <input type ="submit" value="上传"/>    
</form>

不过传统的form表单提交会导致页面刷新,但是很多情况下,我们不希望页面被刷新,这种时候我们都是使用Ajax的方式进行请求的。

formData()形式

const data = new FormData();
data.append('filename', file);

axios({
	method: 'POST',
	url: 'xxx',
	data, //这里data就是一个FormData实例
	headers: {
		'Content-Type': 'multipart/form-data',
		timeout: 10000,
		withCredentials: true
	}
})

如果是需要对多个文件同时上传,直接在fd后面继续append 文件即可,而不用另外new新的FormData实例:

const fd = new FormData();
fd.append('file', file1);
fd.append('file', file2);
fd.append('file', file3);
...

同时axios等增大timeout:

{
  headers: {
    Pragma: 'no-chche',
    'Cache-Control': 'no-cache',
    'Content-Type': 'multipart/form-data'
  },
  timeout: 5 * 60 * 1000
}

特点

增加了ajax对二进制文件上传的支持:

var formData = new FormData();
formData.append("username", "sam");
// HTML file input, chosen by user
formData.append("userfile", fileInputElement.files[0]);
// JavaScript file-like object
var content = 'hey!'; // the body of the new file...
var blob = new Blob([content], { type: "text/xml"});
formData.append("webmasterfile", blob);
var request = new XMLHttpRequest();
request.open("POST", url);
request.send(formData);

获取或修改FormData方式

方案1:创建一个空的FormData对象,然后再用append方法逐个添加键值对:

var formdata = new FormData();
formdata.append("name", "呵呵");
formdata.append("url", "http://www.baidu.com/");

方案2:取得form元素对象,将它作为参数传入FormData对象中!

var formobj =  document.getElementById("form");
var formdata = new FormData(formobj);

方案3:利用form元素对象的getFormData方法生成它!

var formobj =  document.getElementById("form");
var formdata = formobj.getFormData()

内置API方法

  • FormData.append
  • FormData.delete
  • FormData.get
  • FormData.getAll
  • FormData.has
  • FormData.set

FormData.append

formData.append(name, value);
formData.append(name, value, filename);

传给服务器的文件名称,当传入时,会作为value的文件名称。

atob、btoa: 用来处理解码和编码 base64 字符串

可以使用 window.btoa() 方法来编码一个可能在传输过程中出现问题的数据,并且在接受数据之后,使用 atob() 方法再将数据解码。例如:你可以编码、传输和解码操作各种字符,比如 0-31 的 ASCII 码值。

btoa

从 String 对象中创建一个 base-64 编码的 ASCII 字符串,其中字符串中的每个字符都被视为一个二进制数据字节。

window.btoa(stringToEncode);

atob

对经过 base-64 编码的字符串进行解码。

let encodedData = window.btoa("Hello, world"); // 编码
let decodedData = window.atob(encodedData);    // 解码

参考

细说Web API中的Blob
new FormData() 前端上传文件图片到服务器

@kekobin kekobin changed the title FileReader 和 Blob FileReader、Blob、FormData、atob Sep 26, 2019
@kekobin kekobin changed the title FileReader、Blob、FormData、atob FileReader、Blob、FormData、atob、btoa Sep 27, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant