利用Blob進行文件上傳的完整步驟

BLOB (binary large object),二進制大對象,是一個可以存儲二進制文件的容器。下面這篇文章主要給大家介紹了關於利用Blob進行文件上傳的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下

轉載地址:https://www.jb51.net/article/144934.htm

Blob

Blob,Binary Large Object的縮寫,二進制類型的大對象,代表不可改變的原始數據

在計算機中,BLOB常常是數據庫中用來存儲二進制文件的字段類型。

Blob基本用法

Blob對象

Blob對象指的是字節序列,並且具有size屬性,是字節序列中的字節總數,和一個type屬性,它是小寫的ASCII編碼的字符串表示的媒體類型字節序列。

size:以字節數返回字節序列的大小。獲取時,符合要求的用戶代理必須返回一個FileReader或一個FileReaderSync對象可以讀取的總字節數,如果Blob沒有要讀取的字節,則返回0 。
type:小寫的ASCII編碼字符串表示媒體類型Blob。在獲取時,用戶代理必須Blob以小寫形式返回a類型的ASCII編碼字符串,這樣當它轉換爲字節序列時,它是可解析的MIME類型,或者是空字符串(0字節)如果是類型無法確定。

構造函數

創建blob對象本質上和創建一個其他對象的方式是一樣的,都是使用Blob() 的構造函數來進行創建。 構造函數接受兩個參數:

第一個參數爲一個數據序列,格式可以是ArrayBuffer, ArrayBufferView, Blob, DOMString 
第二個參數是一個包含以下兩個屬性的對象

  • type: MIME的類型,
  • endings: 決定第一個參數的數據格式。默認值爲"transparent",用於指定包含行結束符n的字符串如何被寫入。 它是以下兩個值中的一個: "native",表示行結束符會被更改爲適合宿主操作系統文件系統的換行符; "transparent",表示會保持blob中保存的結束符不變。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

var data1 = "a";

var blob1 = new Blob([data1]);

console.log(blob1); //輸出:Blob {size: 1, type: ""}

 

var debug = {hello: "world"};

var blob = new Blob([JSON.stringify(debug, null, 2)],{type : 'application/json'});

console.log(blob) // 輸出 Blob(22) {size: 22, type: "application/json"}

 

// 創建一個8字節的ArrayBuffer,在其上創建一個每個數組元素爲2字節的“視圖”

var abf = new ArrayBuffer(8)

var abv = new Int16Array(abf)

var bolb_ArrayBuffer = new Blob(abv, {type : 'text/plain'})

console.log(bolb_ArrayBuffer) //輸出 Blob(4) {size: 4, type: "text/plain"}

slice方法

Blob對象有一個slice方法,返回一個新的 Blob對象,包含了源 Blob對象中指定範圍內的數據。

?

1

slice(start, end, contentType)

start: 可選,代表 Blob 裏的下標,表示第一個會被會被拷貝進新的 Blob 的字節的起始位置。如果傳入的是一個負數,那麼這個偏移量將會從數據的末尾從後到前開始計算。
end: 可選,代表的是 Blob 的一個下標,這個下標-1的對應的字節將會是被拷貝進新的Blob 的最後一個字節。如果你傳入了一個負數,那麼這個偏移量將會從數據的末尾從後到前開始計算。
contentType: 可選,給新的 Blob 賦予一個新的文檔類型。這將會把它的 type 屬性設爲被傳入的值。它的默認值是一個空的字符串。

?

1

2

3

4

5

6

var data = "abcdef";

var blob1 = new Blob([data]);

var blob2 = blob1.slice(0,3);

 

console.log(blob1); //輸出:Blob {size: 6, type: ""}

console.log(blob2); //輸出:Blob {size: 3, type: ""}

slice用於文件分片上傳

  • 分片與併發結合,將一個大文件分割成多塊,併發上傳,極大地提高大文件的上傳速度。
  • 當網絡問題導致傳輸錯誤時,只需要重傳出錯分片,而不是整個文件。另外分片傳輸能夠更加實時的跟蹤上傳進度。

分片上傳邏輯如下:

獲取要上傳文件的File對象,根據chunk(每片大小)對文件進行分片
通過post方法輪循上傳每片文件,其中url中拼接querystring用於描述當前上傳的文件信息;post body中存放本次要上傳的二進制數據片段
接口每次返回offset,用於執行下次上傳

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

initUpload();

 

//初始化上傳

function initUpload() {

 var chunk = 100 * 1024; //每片大小

 var input = document.getElementById("file"); //input file

 input.onchange = function (e) {

  var file = this.files[0];

  var query = {};

  var chunks = [];

  if (!!file) {

   var start = 0;

   //文件分片

   for (var i = 0; i < Math.ceil(file.size / chunk); i++) {

    var end = start + chunk;

    chunks[i] = file.slice(start , end);

    start = end;

   }

    

   // 採用post方法上傳文件

   // url query上拼接以下參數,用於記錄上傳偏移

   // post body中存放本次要上傳的二進制數據

   query = {

    fileSize: file.size,

    dataSize: chunk,

    nextOffset: 0

   }

 

   upload(chunks, query, successPerUpload);

  }

 }

}

 

// 執行上傳

function upload(chunks, query, cb) {

 var queryStr = Object.getOwnPropertyNames(query).map(key => {

  return key + "=" + query[key];

 }).join("&");

 var xhr = new XMLHttpRequest();

 xhr.open("POST", "http://xxxx/opload?" + queryStr);

 xhr.overrideMimeType("application/octet-stream");

  

 //獲取post body中二進制數據

 var index = Math.floor(query.nextOffset / query.dataSize);

 getFileBinary(chunks[index], function (binary) {

  if (xhr.sendAsBinary) {

   xhr.sendAsBinary(binary);

  } else {

   xhr.send(binary);

  }

 

 });

 

 xhr.onreadystatechange = function (e) {

  if (xhr.readyState === 4) {

   if (xhr.status === 200) {

    var resp = JSON.parse(xhr.responseText);

    // 接口返回nextoffset

    // resp = {

    //  isFinish:false,

    //  offset:100*1024

    // }

    if (typeof cb === "function") {

     cb.call(this, resp, chunks, query)

    }

   }

  }

 }

}

 

// 每片上傳成功後執行

function successPerUpload(resp, chunks, query) {

 if (resp.isFinish === true) {

  alert("上傳成功");

 } else {

  //未上傳完畢

  query.offset = resp.offset;

  upload(chunks, query, successPerUpload);

 }

}

 

// 獲取文件二進制數據

function getFileBinary(file, cb) {

 var reader = new FileReader();

 reader.readAsArrayBuffer(file);

 reader.onload = function (e) {

  if (typeof cb === "function") {

   cb.call(this, this.result);

  }

 }

}

Blob URL

blob協議的url使用時就像平時使用的url一樣,可以作爲圖片請求地址,也可以作爲文件請求地址。格式:

blob:http://XXX

  • URL.createObjectURL(blob) 創建鏈接
  • URL.revokeObjectURL(url)

下面是一個下載文件的示例,直接調用即可實現文件下載

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

// file是要下載的文件(blob對象)

downloadHandler: function (file, fileName) {

 let link = document.createElement('a')

 link.href = window.URL.createObjectURL(file)

 link.download = fileName

 link.click()

 window.URL.revokeObjectURL(link.href)

 if (navigator.userAgent.indexOf('Firefox') > -1) {

 const a = document.createElement('a')

 a.addEventListener('click', function (e) {

  a.download = fileName

  a.href = URL.createObjectURL(file)

 })

 let e = document.createEvent('MouseEvents')

 e.initEvent('click', false, false)

 a.dispatchEvent(e)

 }

}

在從後臺獲取的數據接口中把返回類型設置爲blob

?

1

2

var x = new XMLHttpRequest();

x.responseType = 'blob'// 返回一個blob對象

Blob URL和Data URL的區別

Blob URL

Data URL

  • Blob URL的長度一般比較短,但Data URL因爲直接存儲圖片base64編碼後的數據,往往很長,如上圖所示,瀏覽器在顯示Data URL時使用了省略號(…)。當顯式大圖片時,使用Blob URL能獲取更好的可能性。
  • Blob URL可以方便的使用XMLHttpRequest獲取源數據,比如設置XMLHttpRequest返回的數據類型爲blob
  • Blob URL 只能在當前應用內部使用,把Blob URL複製到瀏覽器的地址欄中,是無法獲取數據的。Data URL相比之下,就有很好的移植性,可以在任意瀏覽器中使用。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章