、FileReader是用于讀取字符流。 要讀取原始字節(jié)流,請(qǐng)考慮使用FileInputStream 。
2、FileReader構(gòu)造方法
1、public FileReader(String fileName) throws FileNotFoundException
解釋:創(chuàng)建一個(gè)新的 FileReader ,給定要讀取的文件的名稱。
參數(shù):fileName - 要讀取的文件的名稱
異常:FileNotFoundException - 如果命名文件不存在,是一個(gè)目錄,而不是常規(guī)文件,或者由于某些其他原因無法打開讀取。
2、public FileReader(File file) throws FileNotFoundException
解釋:創(chuàng)建一個(gè)新的 FileReader ,給定 File讀取。
參數(shù):file - 要閱讀的 File
異常:FileNotFoundException - 如果文件不存在,是一個(gè)目錄而不是常規(guī)文件,或者由于某些其他原因無法打開閱讀。
3、常用方法
1、public int read() throws IOException
讀一個(gè)字符 該方法將阻塞,直到字符可用,發(fā)生I / O錯(cuò)誤或達(dá)到流的結(jié)尾。
結(jié)果 :字符讀取,作為0到65535( 0x00-0xffff )范圍內(nèi)的整數(shù),如果已經(jīng)達(dá)到流的末尾,則為-1。
2、public int read(char[] cbuf) throws IOException
將字符讀入數(shù)組。 該方法將阻塞,直到某些輸入可用,發(fā)生I / O錯(cuò)誤或達(dá)到流的結(jié)尾。
參數(shù) :cbuf - 目的緩沖區(qū)
結(jié)果: 讀取的字符數(shù),如果已經(jīng)達(dá)到流的結(jié)尾,則為-1
4、將D盤的a.txt文件讀取到程序中,并打印到控制臺(tái)
package pro1;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
public class $Test03 {
public static void main(String[] args) throws Exception {
//源目錄
String sourcePath="D:\\a.txt";
//初始化字符輸入流
FileReader fileReader=null;
//定義int類型變量resultData:用于接收read方法讀取的字符值
int resultData=0;
try {
//將字符輸入流和sourcePath關(guān)聯(lián)起來
fileReader=new FileReader(sourcePath);
//循環(huán)讀取fileReader字符輸入流中字符,每次讀取一個(gè)字符
while ((resultData=fileReader.read()) !=-1) {
System.out.print((char)resultData);
}
} catch (Exception e) {
// TODO: handle exception
}finally {
fileReader.close();
}
}
}
第二種方法:通過字符數(shù)組讀?。?/p>
.檢測(cè)瀏覽器對(duì)FileReader兼容性的方法:
if(window.FileReader) {
var fr=new FileReader();
// add your code here
}
else {
alert("Not supported by your browser!");
}
方法二:檢測(cè)FileReader類型
if(typeof FileReader==='undefined'){
alert('您的瀏覽器不支持圖片上傳,請(qǐng)升級(jí)您的瀏覽器');
return false;
}
2.調(diào)用fileReader對(duì)象的方法
FileReader實(shí)例擁有四個(gè)方法, 其中三個(gè)是用來讀取文件, 另一個(gè)是用來中斷讀取的。需要注意的是, 無論讀取成功或是失敗, 方法并不會(huì)返回讀取結(jié)果,
這一結(jié)果(儲(chǔ)存在result屬性中)要用FileReader處理事件去獲取;
方法名 參數(shù) 描述
abort none 中斷讀取
readAsBinaryString file 將文件轉(zhuǎn)化為二進(jìn)制碼
readAsDataURL file 讀取文件內(nèi)容, 結(jié)果用data:url的字符串形式表示
readAsText file,[encoding] 將文件讀取為文本
readAsText:該方法有兩個(gè)參數(shù), 其中第二個(gè)參數(shù)是文本的編碼方式, 默認(rèn)值為 UTF-8。這個(gè)方法非常容易理解, 將文件以文本方式讀取, 讀取的結(jié)果即是這個(gè)文本文件中的內(nèi)容。
readAsText(file,encoding)可按指定編碼方式讀取文件, 但讀取文件的單位是字符, 故對(duì)于文本文件, 只要按規(guī)定的編碼方式讀取即可; 而對(duì)于媒體文件(圖片、音頻、視頻),
其內(nèi)部組成并不是按字符排列, 故采用readAsText讀取, 會(huì)產(chǎn)生亂碼, 因此不是最理想的讀取文件的方式。
readAsBinaryString:該方法將文件讀取為二進(jìn)制字符串, 通常我們將它傳送到后端, 后端可以通過這段字符串存儲(chǔ)文件。
readAsDataURL:這是例子程序中用到的方法, 該方法將文件讀取為一段以 data: 開頭的字符串, 這段字符串的實(shí)質(zhì)就是 Data URL, Data URL是一種將小文件直接嵌入文檔的方案。
這里的小文件通常是指圖像與 html 等格式的文件。控制臺(tái)為當(dāng)前所傳文件的base64編碼表示。
由于媒體文件的src屬性, 可以通過采用網(wǎng)絡(luò)地址或base64的方式顯示,因此我們可以利用readAsDataURL實(shí)現(xiàn)對(duì)圖片的預(yù)覽。
3.處理事件
FileReader 包含了一整套完成的事件模型,用于捕獲讀取文件時(shí)的狀態(tài),下面這個(gè)表格歸納了這些事件。
事件 描述
onabort 中斷時(shí)觸發(fā)
onerror 出錯(cuò)時(shí)觸發(fā)
onload 文件讀取成功完成時(shí)觸發(fā)
onloadend 讀取完成時(shí)觸發(fā),無論讀取成功或失敗
onloadstart 讀取開始時(shí)觸發(fā)
onprogress 讀取中
result 返回文件的內(nèi)容。只有在讀取操作完成后,此屬性才有效,返回的數(shù)據(jù)的格式取決于是使用哪種讀取方法來執(zhí)行讀取操作的。
readyState 提供 FileReader 讀取操作時(shí)的當(dāng)前狀態(tài)。
家好,我是 Echa。
好久沒跟粉絲們細(xì)聊JavaScript那點(diǎn)事了。做一名全棧工程師,JS基礎(chǔ)還是要打牢,這樣的話不管底層業(yè)務(wù)邏輯以及第三方框架怎么變化,都離不開基礎(chǔ)。本文文章屬于基礎(chǔ)篇,閱讀有點(diǎn)乏味枯燥,但一定能學(xué)到知識(shí)。創(chuàng)作不易,喜歡的老鐵們加個(gè)關(guān)注,點(diǎn)個(gè)贊,后面會(huì)持續(xù)更新干貨,速速收藏,謝謝!
JavaScript 提供了一些 API 來處理文件或原始文件數(shù)據(jù),例如:File、Blob、FileReader、ArrayBuffer、base64 等。下面就來看看它們都是如何使用的,它們之間又有何區(qū)別和聯(lián)系!
上面的這個(gè)圖是在線工具畫的,打開就可以用的網(wǎng)址如下:
https://excalidraw.com/
Blob 全稱為 binary large object ,即二進(jìn)制大對(duì)象,它是 JavaScript 中的一個(gè)對(duì)象,表示原始的類似文件的數(shù)據(jù)。下面是 MDN 中對(duì) Blob 的解釋:
Blob 對(duì)象表示一個(gè)不可變、原始數(shù)據(jù)的類文件對(duì)象。它的數(shù)據(jù)可以按文本或二進(jìn)制的格式進(jìn)行讀取,也可以轉(zhuǎn)換成 ReadableStream 來用于數(shù)據(jù)操作。
實(shí)際上,Blob 對(duì)象是包含有只讀原始數(shù)據(jù)的類文件對(duì)象。簡(jiǎn)單來說,Blob 對(duì)象就是一個(gè)不可修改的二進(jìn)制文件。
可以使用 Blob() 構(gòu)造函數(shù)來創(chuàng)建一個(gè) Blob:
new Blob(array, options);
其有兩個(gè)參數(shù):
常見的 MIME 類型如下:
下面來看一個(gè)簡(jiǎn)單的例子:
const blob=new Blob(["Hello World"], {type: "text/plain"});
這里可以成為動(dòng)態(tài)文件創(chuàng)建,其正在創(chuàng)建一個(gè)類似文件的對(duì)象。這個(gè) blob 對(duì)象上有兩個(gè)屬性:
下面來看打印結(jié)果:
const blob=new Blob(["Hello World"], {type: "text/plain"});
console.log(blob.size); // 11
console.log(blob.type); // "text/plain"
注意,字符串"Hello World"是 UTF-8 編碼的,因此它的每個(gè)字符占用 1 個(gè)字節(jié)。
到現(xiàn)在,Blob 對(duì)象看起來似乎我們還是沒有啥用。那該如何使用 Blob 對(duì)象呢?可以使用 URL.createObjectURL() 方法將將其轉(zhuǎn)化為一個(gè) URL,并在 Iframe 中加載:
<iframe></iframe>
const iframe=document.getElementsByTagName("iframe")[0];
const blob=new Blob(["Hello World"], {type: "text/plain"});
iframe.src=URL.createObjectURL(blob);
除了使用Blob()構(gòu)造函數(shù)來創(chuàng)建blob 對(duì)象之外,還可以從 blob 對(duì)象中創(chuàng)建blob,也就是將 blob 對(duì)象切片。Blob 對(duì)象內(nèi)置了 slice() 方法用來將 blob 對(duì)象分片,其語法如下:
const blob=instanceOfBlob.slice([start [, end [, contentType]]]};
其有三個(gè)參數(shù):
下面來看例子:
const iframe=document.getElementsByTagName("iframe")[0];
const blob=new Blob(["Hello World"], {type: "text/plain"});
const subBlob=blob.slice(0, 5);
iframe.src=URL.createObjectURL(subBlob);
此時(shí)頁面會(huì)顯示"Hello"。
文件(File)接口提供有關(guān)文件的信息,并允許網(wǎng)頁中的 JavaScript 訪問其內(nèi)容。實(shí)際上,F(xiàn)ile 對(duì)象是特殊類型的 Blob,且可以用在任意的 Blob 類型的 context 中。Blob 的屬性和方法都可以用于 File 對(duì)象。
注意:File 對(duì)象中只存在于瀏覽器環(huán)境中,在 Node.js 環(huán)境中不存在。
在 JavaScript 中,主要有兩種方法來獲取 File 對(duì)象:
首先定義一個(gè)輸入類型為 file 的 input 標(biāo)簽:
<input type="file" id="fileInput" multiple="multiple">
這里給 input 標(biāo)簽添加了三個(gè)屬性:
下面來給 input 標(biāo)簽添加 onchange 事件,當(dāng)選擇文件并上傳之后觸發(fā):
const fileInput=document.getElementById("fileInput");
fileInput.onchange=(e)=> {
console.log(e.target.files);
}
當(dāng)點(diǎn)擊上傳文件時(shí),控制臺(tái)就會(huì)輸出一個(gè) FileList 數(shù)組,這個(gè)數(shù)組的每個(gè)元素都是一個(gè) File 對(duì)象,一個(gè)上傳的文件就對(duì)應(yīng)一個(gè) File 對(duì)象:
每個(gè) File 對(duì)象都包含文件的一些屬性,這些屬性都繼承自 Blob 對(duì)象:
通常,我們?cè)谏蟼魑募r(shí),可以通過對(duì)比 size 屬性來限制文件大小,通過對(duì)比 type 來限制上傳文件的格式等。
另一種獲取 File 對(duì)象的方式就是拖放 API,這個(gè) API 很簡(jiǎn)單,就是將瀏覽器之外的文件拖到瀏覽器窗口中,并將它放在一個(gè)成為拖放區(qū)域的特殊區(qū)域中。拖放區(qū)域用于響應(yīng)放置操作并從放置的項(xiàng)目中提取信息。這些是通過 ondrop 和 ondragover 兩個(gè) API 實(shí)現(xiàn)的。
下面來看一個(gè)簡(jiǎn)單的例子,首先定義一個(gè)拖放區(qū)域:
<div id="drop-zone"></div>
然后給這個(gè)元素添加 ondragover 和 ondrop 事件處理程序:
const dropZone=document.getElementById("drop-zone");
dropZone.ondragover=(e)=> {
e.preventDefault();
}
dropZone.ondrop=(e)=> {
e.preventDefault();
const files=e.dataTransfer.files;
console.log(files)
}
注意:這里給兩個(gè) API 都添加了 e.preventDefault(),用來阻止默認(rèn)事件。它是非常重要的,可以用來阻止瀏覽器的一些默認(rèn)行為,比如放置文件將顯示在瀏覽器窗口中。
當(dāng)拖放文件到拖放區(qū)域時(shí),控制臺(tái)就會(huì)輸出一個(gè) FileList 數(shù)組,該數(shù)組的每一個(gè)元素都是一個(gè) File 對(duì)象。這個(gè) FileList 數(shù)組是從事件參數(shù)的 dataTransfer 屬性的 files 獲取的:
可以看到,這里得到的 File 對(duì)象和通過 input 標(biāo)簽獲得的 File 對(duì)象是完全一樣的。
FileReader 是一個(gè)異步 API,用于讀取文件并提取其內(nèi)容以供進(jìn)一步使用。FileReader 可以將 Blob 讀取為不同的格式。
注意:FileReader 僅用于以安全的方式從用戶(遠(yuǎn)程)系統(tǒng)讀取文件內(nèi)容,不能用于從文件系統(tǒng)中按路徑名簡(jiǎn)單地讀取文件。
可以使用 FileReader 構(gòu)造函數(shù)來創(chuàng)建一個(gè) FileReader 對(duì)象:
const reader=new FileReader();
這個(gè)對(duì)象常用屬性如下:
FileReader 對(duì)象提供了以下方法來加載文件:
可以看到,上面這些方法都接受一個(gè)要讀取的 blob 對(duì)象作為參數(shù),讀取完之后會(huì)將讀取的結(jié)果放入對(duì)象的 result 屬性中。
FileReader 對(duì)象常用的事件如下:
當(dāng)然,這些方法可以加上前置 on 后在HTML元素上使用,比如onload、onerror、onabort、onprogress。除此之外,由于FileReader對(duì)象繼承自EventTarget,因此還可以使用 addEventListener() 監(jiān)聽上述事件。
下面來看一個(gè)簡(jiǎn)單的例子,首先定義一個(gè) input 輸入框用于上傳文件:
<input type="file" id="fileInput">
接下來定義 input 標(biāo)簽的 onchange 事件處理函數(shù)和FileReader對(duì)象的onload事件處理函數(shù):
const fileInput=document.getElementById("fileInput");
const reader=new FileReader();
fileInput.onchange=(e)=> {
reader.readAsText(e.target.files[0]);
}
reader.onload=(e)=> {
console.log(e.target.result);
}
這里,首先創(chuàng)建了一個(gè) FileReader 對(duì)象,當(dāng)文件上傳成功時(shí),使用 readAsText() 方法讀取 File 對(duì)象,當(dāng)讀取操作完成時(shí)打印讀取結(jié)果。
使用上述例子讀取文本文件時(shí),就是比較正常的。如果讀取二進(jìn)制文件,比如png格式的圖片,往往會(huì)產(chǎn)生亂碼,如下:
那該如何處理這種二進(jìn)制數(shù)據(jù)呢?readAsDataURL() 是一個(gè)不錯(cuò)的選擇,它可以將讀取的文件的內(nèi)容轉(zhuǎn)換為 base64 數(shù)據(jù)的 URL 表示。這樣,就可以直接將 URL 用在需要源鏈接的地方,比如 img 標(biāo)簽的 src 屬性。
對(duì)于上述例子,將 readAsText 方法改為 readAsDataURL():
const fileInput=document.getElementById("fileInput");
const reader=new FileReader();
fileInput.onchange=(e)=> {
reader.readAsDataURL(e.target.files[0]);
}
reader.onload=(e)=> {
console.log(e.target.result);
}
這時(shí),再次上傳二進(jìn)制圖片時(shí),就會(huì)在控制臺(tái)打印一個(gè) base64 編碼的 URL,如下:
下面來修改一下這個(gè)例子,將上傳的圖片通過以上方式顯示在頁面上:
<input type="file" id="fileInput" />
<img id="preview" />
const fileInput=document.getElementById("fileInput");
const preview=document.getElementById("preview");
const reader=new FileReader();
fileInput.onchange=(e)=> {
reader.readAsDataURL(e.target.files[0]);
};
reader.onload=(e)=> {
preview.src=e.target.result;
console.log(e.target.result);
};
當(dāng)上傳大文件時(shí),可以通過 progress 事件來監(jiān)控文件的讀取進(jìn)度:
const reader=new FileReader();
reader.onprogress=(e)=> {
if (e.loaded && e.total) {
const percent=(event.loaded / event.total) * 100;
console.log(`上傳進(jìn)度: ${Math.round(percent)} %`);
}
});
progress 事件提供了兩個(gè)屬性:loaded(已讀取量)和total(需讀取總量)。
ArrayBuffer 對(duì)象用來表示通用的、固定長(zhǎng)度的原始二進(jìn)制數(shù)據(jù)緩沖區(qū)。ArrayBuffer 的內(nèi)容不能直接操作,只能通過 DataView 對(duì)象或 TypedArrray 對(duì)象來訪問。這些對(duì)象用于讀取和寫入緩沖區(qū)內(nèi)容。
ArrayBuffer 本身就是一個(gè)黑盒,不能直接讀寫所存儲(chǔ)的數(shù)據(jù),需要借助以下視圖對(duì)象來讀寫:
TypedArray視圖和 DataView視圖的區(qū)別主要是字節(jié)序,前者的數(shù)組成員都是同一個(gè)數(shù)據(jù)類型,后者的數(shù)組成員可以是不同的數(shù)據(jù)類型。
那 ArrayBuffer 與 Blob 有啥區(qū)別呢?根據(jù) ArrayBuffer 和 Blob 的特性,Blob 作為一個(gè)整體文件,適合用于傳輸;當(dāng)需要對(duì)二進(jìn)制數(shù)據(jù)進(jìn)行操作時(shí)(比如要修改某一段數(shù)據(jù)時(shí)),就可以使用 ArrayBuffer。
下面來看看 ArrayBuffer 有哪些常用的方法和屬性。
ArrayBuffer 可以通過以下方式生成:
new ArrayBuffer(bytelength)
ArrayBuffer()構(gòu)造函數(shù)可以分配指定字節(jié)數(shù)量的緩沖區(qū),其參數(shù)和返回值如下:
ArrayBuffer 實(shí)例上有一個(gè) byteLength 屬性,它是一個(gè)只讀屬性,表示 ArrayBuffer 的 byte 的大小,在 ArrayBuffer 構(gòu)造完成時(shí)生成,不可改變。來看例子:
const buffer=new ArrayBuffer(16);
console.log(buffer.byteLength); // 16
ArrayBuffer 實(shí)例上還有一個(gè) slice 方法,該方法可以用來截取 ArrayBuffer 實(shí)例,它返回一個(gè)新的 ArrayBuffer ,它的內(nèi)容是這個(gè) ArrayBuffer 的字節(jié)副本,從 begin(包括),到 end(不包括)。來看例子:
const buffer=new ArrayBuffer(16);
console.log(buffer.slice(0, 8)); // 16
這里會(huì)從 buffer 對(duì)象上將前8個(gè)字節(jié)生成一個(gè)新的ArrayBuffer對(duì)象。這個(gè)方法實(shí)際上有兩步操作,首先會(huì)分配一段指定長(zhǎng)度的內(nèi)存,然后拷貝原來ArrayBuffer對(duì)象的置頂部分。
ArrayBuffer 上有一個(gè) isView()方法,它的返回值是一個(gè)布爾值,如果參數(shù)是 ArrayBuffer 的視圖實(shí)例則返回 true,例如類型數(shù)組對(duì)象或 DataView 對(duì)象;否則返回 false。簡(jiǎn)單來說,這個(gè)方法就是用來判斷參數(shù)是否是 TypedArray 實(shí)例或者 DataView 實(shí)例:
const buffer=new ArrayBuffer(16);
ArrayBuffer.isView(buffer) // false
const view=new Uint32Array(buffer);
ArrayBuffer.isView(view) // true
TypedArray 對(duì)象一共提供 9 種類型的視圖,每一種視圖都是一種構(gòu)造函數(shù)。如下:
元素類型化數(shù)組字節(jié)描述Int8Int8Array18 位有符號(hào)整數(shù)Uint8Uint8Array18 位無符號(hào)整數(shù)Uint8CUint8ClampedArray18 位無符號(hào)整數(shù)Int16Int16Array216 位有符號(hào)整數(shù)Uint16Uint16Array216 位無符號(hào)整數(shù)Int32Int32Array432 位有符號(hào)整數(shù)Uint32Uint32Array432 位無符號(hào)整數(shù)Float32Float32Array432 位浮點(diǎn)Float64Float64Array864 位浮點(diǎn)
來看看這些都是什么意思:
這些構(gòu)造函數(shù)生成的對(duì)象統(tǒng)稱為 TypedArray 對(duì)象。它們和正常的數(shù)組很類似,都有length屬性,都能用索引獲取數(shù)組元素,所有數(shù)組的方法都可以在類型化數(shù)組上面使用。
那類型化數(shù)組和數(shù)組有什么區(qū)別呢?
下面來看看 TypedArray 都有哪些常用的方法和屬性。
TypedArray 的語法如下(TypedArray只是一個(gè)概念,實(shí)際使用的是那9個(gè)對(duì)象):
new Int8Array(length);
new Int8Array(typedArray);
new Int8Array(object);
new Int8Array(buffer [, byteOffset [, length]]);
可以看到,TypedArray 有多種用法,下面來分別看一下。
let view=new Int8Array(16);
view[0]=10;
view[10]=6;
console.log(view);
輸出結(jié)果如下:
這里就生成了一個(gè) 16個(gè)元素的 Int8Array 數(shù)組,除了手動(dòng)賦值的元素,其他元素的初始值都是 0。
const view=new Int8Array(new Uint8Array(6));
view[0]=10;
view[3]=6;
console.log(view);
輸出結(jié)果如下:
const view=new Int8Array([1, 2, 3, 4, 5]);
view[0]=10;
view[3]=6;
console.log(view);
輸出結(jié)果如下:
需要注意,TypedArray視圖會(huì)開辟一段新的內(nèi)存,不會(huì)在原數(shù)組上建立內(nèi)存。當(dāng)然,這里創(chuàng)建的類型化數(shù)組也能轉(zhuǎn)換回普通數(shù)組:
Array.prototype.slice.call(view); // [10, 2, 3, 6, 5]
這種方式有三個(gè)參數(shù),其中第一個(gè)參數(shù)是一個(gè)ArrayBuffer對(duì)象;第二個(gè)參數(shù)是視圖開始的字節(jié)序號(hào),默認(rèn)從0開始,可選;第三個(gè)參數(shù)是視圖包含的數(shù)據(jù)個(gè)數(shù),默認(rèn)直到本段內(nèi)存區(qū)域結(jié)束。
const buffer=new ArrayBuffer(8);
const view1=new Int32Array(buffer);
const view2=new Int32Array(buffer, 4);
console.log(view1, view2);
輸出結(jié)果如下:
每種視圖的構(gòu)造函數(shù)都有一個(gè) BYTES_PER_ELEMENT 屬性,表示這種數(shù)據(jù)類型占據(jù)的字節(jié)數(shù):
Int8Array.BYTES_PER_ELEMENT // 1
Uint8Array.BYTES_PER_ELEMENT // 1
Int16Array.BYTES_PER_ELEMENT // 2
Uint16Array.BYTES_PER_ELEMENT // 2
Int32Array.BYTES_PER_ELEMENT // 4
Uint32Array.BYTES_PER_ELEMENT // 4
Float32Array.BYTES_PER_ELEMENT // 4
Float64Array.BYTES_PER_ELEMENT // 8
BYTES_PER_ELEMENT 屬性也可以在類型化數(shù)組的實(shí)例上獲?。?/p>
const buffer=new ArrayBuffer(16);
const view=new Uint32Array(buffer);
console.log(Uint32Array.BYTES_PER_ELEMENT); // 4
TypedArray 實(shí)例的 buffer 屬性會(huì)返回內(nèi)存中對(duì)應(yīng)的 ArrayBuffer對(duì)象,只讀屬性。
const a=new Uint32Array(8);
const b=new Int32Array(a.buffer);
console.log(a, b);
輸出結(jié)果如下:
TypeArray 實(shí)例的 slice方法可以返回一個(gè)指定位置的新的 TypedArray實(shí)例。
const view=new Int16Array(8);
console.log(view.slice(0 ,5));
輸出結(jié)果如下:
const view=new Int16Array(8);
view.length; // 8
view.byteLength; // 16
說完 ArrayBuffer,下面來看看另一種操作 ArrayBuffer 的方式:DataView。DataView 視圖是一個(gè)可以從 二進(jìn)制 ArrayBuffer 對(duì)象中讀寫多種數(shù)值類型的底層接口,使用它時(shí),不用考慮不同平臺(tái)的字節(jié)序問題。
DataView視圖提供更多操作選項(xiàng),而且支持設(shè)定字節(jié)序。本來,在設(shè)計(jì)目的上,ArrayBuffer對(duì)象的各種TypedArray視圖,是用來向網(wǎng)卡、聲卡之類的本機(jī)設(shè)備傳送數(shù)據(jù),所以使用本機(jī)的字節(jié)序就可以了;而DataView視圖的設(shè)計(jì)目的,是用來處理網(wǎng)絡(luò)設(shè)備傳來的數(shù)據(jù),所以大端字節(jié)序或小端字節(jié)序是可以自行設(shè)定的。
DataView視圖可以通過構(gòu)造函數(shù)來創(chuàng)建,它的參數(shù)是一個(gè)ArrayBuffer對(duì)象,生成視圖。其語法如下:
new DataView(buffer [, byteOffset [, byteLength]])
其有三個(gè)參數(shù):
來看一個(gè)例子:
const buffer=new ArrayBuffer(16);
const view=new DataView(buffer);
console.log(view);
打印結(jié)果如下:
DataView 實(shí)例有以下常用屬性:
const buffer=new ArrayBuffer(16);
const view=new DataView(buffer);
view.buffer;
view.byteLength;
view.byteOffset;
打印結(jié)果如下:
DataView 實(shí)例提供了以下方法來讀取內(nèi)存,它們的參數(shù)都是一個(gè)字節(jié)序號(hào),表示開始讀取的字節(jié)位置:
下面來看一個(gè)例子:
const buffer=new ArrayBuffer(24);
const view=new DataView(buffer);
// 從第1個(gè)字節(jié)讀取一個(gè)8位無符號(hào)整數(shù)
const view1=view.getUint8(0);
// 從第2個(gè)字節(jié)讀取一個(gè)16位無符號(hào)整數(shù)
const view2=view.getUint16(1);
// 從第4個(gè)字節(jié)讀取一個(gè)16位無符號(hào)整數(shù)
const view3=view.getUint16(3);
DataView 實(shí)例提供了以下方法來寫入內(nèi)存,它們都接受兩個(gè)參數(shù),第一個(gè)參數(shù)表示開始寫入數(shù)據(jù)的字節(jié)序號(hào),第二個(gè)參數(shù)為寫入的數(shù)據(jù):
Object URL(MDN定義名稱)又稱Blob URL(W3C定義名稱),是HTML5中的新標(biāo)準(zhǔn)。它是一個(gè)用來表示File Object 或Blob Object 的URL。在網(wǎng)頁中,我們可能會(huì)看到過這種形式的 Blob URL:
其實(shí) Blob URL/Object URL 是一種偽協(xié)議,允許將 Blob 和 File 對(duì)象用作圖像、二進(jìn)制數(shù)據(jù)下載鏈接等的 URL 源。
對(duì)于 Blob/File 對(duì)象,可以使用 URL構(gòu)造函數(shù)的 createObjectURL() 方法創(chuàng)建將給出的對(duì)象的 URL。這個(gè) URL 對(duì)象表示指定的 File 對(duì)象或 Blob 對(duì)象。我們可以在<img>、<script> 標(biāo)簽中或者 <a> 和 <link> 標(biāo)簽的 href 屬性中使用這個(gè) URL。
來看一個(gè)簡(jiǎn)單的例子,首先定義一個(gè)文件上傳的 input 和一個(gè) 圖片預(yù)覽的 img:
<input type="file" id="fileInput" />
<img id="preview" />
再來使用 URL.createObjectURL() 將File 對(duì)象轉(zhuǎn)化為一個(gè) URL:
const fileInput=document.getElementById("fileInput");
const preview=document.getElementById("preview");
fileInput.onchange=(e)=> {
preview.src=URL.createObjectURL(e.target.files[0]);
console.log(preview.src);
};
可以看到,上傳的圖片轉(zhuǎn)化成了一個(gè) URL,并顯示在了屏幕上:
那這個(gè) API 有什么意義呢?可以將Blob/File對(duì)象轉(zhuǎn)化為URL,通過這個(gè)URL 就可以實(shí)現(xiàn)文件下載或者圖片顯示等。
當(dāng)我們使用createObjectURL()方法創(chuàng)建一個(gè)data URL 時(shí),就需要使用revokeObjectURL()方法從內(nèi)存中清除它來釋放內(nèi)存。雖然瀏覽器會(huì)在文檔卸載時(shí)自動(dòng)釋放 Data URL,但為了提高性能,我們應(yīng)該使用revokeObjectURL()來手動(dòng)釋放它。revokeObjectURL()方法接受一個(gè)Data URL 作為其參數(shù),返回undefined。下面來看一個(gè)例子:
const objUrl=URL.createObjectURL(new File([""], "filename"));
console.log(objUrl);
URL.revokeObjectURL(objUrl);
Base64 是一種基于64個(gè)可打印字符來表示二進(jìn)制數(shù)據(jù)的表示方法。Base64 編碼普遍應(yīng)用于需要通過被設(shè)計(jì)為處理文本數(shù)據(jù)的媒介上儲(chǔ)存和傳輸二進(jìn)制數(shù)據(jù)而需要編碼該二進(jìn)制數(shù)據(jù)的場(chǎng)景。這樣是為了保證數(shù)據(jù)的完整并且不用在傳輸過程中修改這些數(shù)據(jù)。
在 JavaScript 中,有兩個(gè)函數(shù)被分別用來處理解碼和編碼 base64 字符串:
btoa("JavaScript") // 'SmF2YVNjcmlwdA=='
atob('SmF2YVNjcmlwdA==') // 'JavaScript'
那 base64 的實(shí)際應(yīng)用場(chǎng)景有哪些呢?其實(shí)多數(shù)場(chǎng)景就是基于Data URL的。比如,使用toDataURL()方法把 canvas 畫布內(nèi)容生成 base64 編碼格式的圖片:
const canvas=document.getElementById('canvas');
const ctx=canvas.getContext("2d");
const dataUrl=canvas.toDataURL();
除此之外,還可以使用readAsDataURL()方法把上傳的文件轉(zhuǎn)為base64格式的data URI,比如上傳頭像展示或者編輯:
<input type="file" id="fileInput" />
<img id="preview" />
const fileInput=document.getElementById("fileInput");
const preview=document.getElementById("preview");
const reader=new FileReader();
fileInput.onchange=(e)=> {
reader.readAsDataURL(e.target.files[0]);
};
reader.onload=(e)=> {
preview.src=e.target.result;
console.log(e.target.result);
};
效果如下,將圖片(二進(jìn)制數(shù)據(jù))轉(zhuǎn)化為可打印的字符,也便于數(shù)據(jù)的傳輸:
另外,一些小的圖片都可以使用 base64 格式進(jìn)行展示,img標(biāo)簽和background的 url 屬性都支持使用base64 格式的圖片,這樣做也可以減少 HTTP 請(qǐng)求。
看完這些基本的概念,下面就來看看常用格式之間是如何轉(zhuǎn)換的。
const blob=new Blob([new Uint8Array(buffer, byteOffset, length)]);
const base64=btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)));
const base64toBlob=(base64Data, contentType, sliceSize)=> {
const byteCharacters=atob(base64Data);
const byteArrays=[];
for (let offset=0; offset < byteCharacters.length; offset +=sliceSize) {
const slice=byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers=new Array(slice.length);
for (let i=0; i < slice.length; i++) {
byteNumbers[i]=slice.charCodeAt(i);
}
const byteArray=new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
const blob=new Blob(byteArrays, {type: contentType});
return blob;
}
function blobToArrayBuffer(blob) {
return new Promise((resolve, reject)=> {
const reader=new FileReader();
reader.onload=()=> resolve(reader.result);
reader.onerror=()=> reject;
reader.readAsArrayBuffer(blob);
});
}
function blobToBase64(blob) {
return new Promise((resolve)=> {
const reader=new FileReader();
reader.onloadend=()=> resolve(reader.result);
reader.readAsDataURL(blob);
});
}
const objectUrl=URL.createObjectURL(blob);
*請(qǐng)認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。