关于文件之间的转换

359 阅读5分钟

Blob

Blob 对象表示一个不可变、原始数据的类文件对象。它的数据可以按文本或二进制的格式进行读取,也可以转换成 ReadableStream 来用于数据操作。 

Blob 表示的不一定是JavaScript原生格式的数据。File 接口基于Blob,继承了 blob 的功能并将其扩展使其支持用户系统上的文件。

要从其他非blob对象和数据构造一个 Blob,请使用 Blob() 构造函数。要创建一个 blob 数据的子集 blob,请使用 slice() 方法。要获取用户文件系统上的文件对应的 Blob 对象,请参阅 File 文档。

接受 Blob 对象的API也被列在 File 文档中。

注意: slice() 方法原本接受 length 作为第二个参数,以表示复制到新 Blob 对象的字节数。如果设置的参数使 start + length 超出了源 Blob 对象的大小,则返回从开始到结尾的所有数据。

注意: slice() 方法在某些浏览器和版本上带有浏览器引擎前缀:比如 Firefox 12 及更早版本的blob.mozSlice() 和 Safari 中的blob.webkitSlice()。 没有浏览器引擎前缀的老版本 slice() 方法有不同的语义,并且已过时。Firefox 30 取消了对 blob.mozSlice() 的支持。

构造函数

属性

  • Blob.size 只读

    Blob 对象中所包含数据的大小(字节)。

  • Blob.type 只读

    一个字符串,表明该 Blob 对象所包含数据的 MIME 类型。如果类型未知,则该值为空字符串。

方法

示例

Blob 构造函数用法举例

Blob() 构造函数允许通过其它对象创建 Blob 对象。比如,用字符串构建一个 blob:

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

示例:使用 Blob 创建一个指向类型化数组的URL

参考下面的代码:

var typedArray = GetTheTypedArraySomehow();
var blob = new Blob([typedArray.buffer], {type: 'application/octet-stream'}); // 传入一个合适的 MIME 类型
var url = URL.createObjectURL(blob);
// 会产生一个类似 blob:d3958f5c-0777-0845-9dcf-2cb28783acaf 这样的URL字符串
// 你可以像使用普通 URL 那样使用它,比如用在 img.src 上。

示例:从 Blob 中提取数据

一种从Blob中读取内容的方法是使用 FileReader。以下代码将 Blob 的内容作为类型数组读取:

var reader = new FileReader();
reader.addEventListener("loadend", function() {
   // reader.result 包含被转化为类型数组 typed array 的 blob
});
reader.readAsArrayBuffer(blob);

另一种读取Blob中内容的方式是使用Response对象。下述代码将Blob中的内容读取为文本:

var text = await (new Response(blob)).text();

通过使用 FileReader 的其它方法可以把 Blob 读取为字符串或者数据URL。

FileReader

FileReader 对象允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据。

其中File对象可以是来自用户在一个<input>元素上选择文件后返回的FileList对象,也可以来自拖放操作生成的 DataTransfer对象,还可以是来自在一个HTMLCanvasElement上执行mozGetAsFile()方法后返回结果。

  • FileReader.result 只读

    文件的内容。该属性仅在读取操作完成后才有效,数据的格式取决于使用哪个方法来启动读取操作。

  • FileReader.onload

  • 处理load事件。该事件在读取操作完成时触发。

方法

  • FileReader.abort()

    中止读取操作。在返回时,readyState属性为DONE

  • FileReader.readAsArrayBuffer()

    FileReader 接口提供的 readAsArrayBuffer()  方法用于启动读取指定的 Blob 或 File 内容。当读取操作完成时,readyState 变成 DONE(已完成),并触发 loadend (en-US) 事件,同时 result 属性中将包含一个 ArrayBuffer 对象以表示所读取文件的数据。

    兼容性: 99.53% image

  • FileReader.readAsBinaryString() 

    开始读取指定的Blob中的内容。一旦完成,result属性中将包含所读取文件的原始二进制数据。

  • FileReader.readAsDataURL()

    开始读取指定的Blob中的内容。一旦完成,result属性中将包含一个data: URL格式的Base64字符串以表示所读取文件的内容。

  • FileReader.readAsText()

    开始读取指定的Blob中的内容。一旦完成,result属性中将包含一个字符串以表示所读取的文件内容。

文件类型之前的转换关系如下图:

微信截图_20200630091759.png

Blob => ArrayBuffer

简短版:

var arrayBuffer;
var fileReader = new FileReader();
fileReader.onload = function(event) {
    arrayBuffer = event.target.result;
};
fileReader.readAsArrayBuffer(blob);

加长版:

// ArrayBuffer -> Blob
var uint8Array  = new Uint8Array([1, 2, 3]);
var arrayBuffer = uint8Array.buffer;
var blob        = new Blob([arrayBuffer]);
// Blob -> ArrayBuffer
var uint8ArrayNew  = null;
var arrayBufferNew = null;
var fileReader     = new FileReader();
fileReader.onload  = function(progressEvent) {
    arrayBufferNew = this.result;
    uint8ArrayNew  = new Uint8Array(arrayBufferNew);

    // warn if read values are not the same as the original values
    // arrayEqual from: http://stackoverflow.com/questions/3115982/how-to-check-javascript-array-equals
    function arrayEqual(a, b) { return !(a<b || b<a); };
    if (arrayBufferNew.byteLength !== arrayBuffer.byteLength) // should be 3
        console.warn("ArrayBuffer byteLength does not match");
    if (!arrayEqual(uint8ArrayNew, uint8Array)) // should be [1,2,3]
        console.warn("Uint8Array does not match");
};
fileReader.readAsArrayBuffer(blob);
fileReader.result; // also accessible this way once the blob has been read

File 转换为 base64 || blob 流转换为 base64

   # 转换关系代码如下:
   /**
    * file 转换为 base64 || blob 流转换为 base64
    * readAsDataURL(Blob|File)             //获取base64编码文件
    * readAsText(Blob|File, opt_encoding)  //获取文本字符串默认情况下,文本编码格式是'UTF-8',可以通过可选的格式参数,指定其他编码格式的文本。
    * readAsArrayBuffer(Blob|File)         //返回一个 ArrayBuffer(数组缓存)对象。
    * readAsBinaryString(Blob|File)        //返回二进制字符串,该字符串每个字节包含一个 0 到 255 之间的整数。
    * abort()                              //该方法用于中止文件上传。
    */
   var reader = new FileReader();
   reader.readAsDataURL(this.files[0]);
   reader.onload = function(){
       console.log(reader.result); 
   };

base64 转换为 File

  /**
   * base64 转换为 file
   * dataurl base64对象
   * filename 文件名
   */
  function dataURLtoFile(dataurl, filename) {//将base64转换为文件
    var arr = dataurl.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 File([u8arr], filename, {type:mime});
  }

base64 转换为 Blob

  /**
   * base64 转换为 blob
   * @param base64    用url方式表示的base64数据
   * @return blob     返回blob对象     
   */
  function convertBase64UrlToBlob(base64){
      var type =base64.split(",")[0].match(/:(.*?);/)[1];//提取base64头的type如 'image/png'     
      var bytes=window.atob(base64.split(',')[1]);//去掉url的头,并转换为byte (atob:编码 btoa:解码)

      //处理异常,将ascii码小于0的转换为大于0 
      var ab = new ArrayBuffer(bytes.length);//通用的、固定长度(bytes.length)的原始二进制数据缓冲区对象
      var ia = new Uint8Array(ab);
      for (var i = 0; i < bytes.length; i++) {
          ia[i] = bytes.charCodeAt(i);
      }
      return new Blob( [ab] , {type :type});
  }

blob 转换为 File

 /**
  * blob 转换为 file
  */
 var file = new File([byteArrays], filename, {type: contentType, lastModified: Date.now()});
 // 或
 var blob = new Blob(byteArrays, { type: contentType });
 var file = new File([blob], fileName, {type: fileType, lastModified: Date.now()});

URL 到 File 转换过程全部分解 

/**
 * DataURL 到 file 转换过程全部分解 
 * DataURL 转换为 blob 
 * DataURL 转换为 base64
 * fileName 文件名
 * 注解清晰,酌情分解,如果不是url类型获取 不需要此方法,参考以上方法
 */
function getBase64(imgUrl,callback) {
  window.URL = window.URL || window.webkitURL;
  var xhr = new XMLHttpRequest();
  xhr.open("get", imgUrl, true);
  // 至关重要
  xhr.responseType = "blob";
  xhr.onload = function () {
    if (this.status == 200) {
        /**
         * DataURL 转换为 blob 
         */
        var blob = this.response;
        var blobUrl = window.URL.createObjectURL(blob);
        // callback.call(this, blobUrl); 
        /**
         * blob 转换为 file
         */
        var file = new File([blob], fileName, {type: fileType, lastModified: Date.now()});
        formData.append(fileName, file);
        /**
         * blob 转换为 base64
         */
        var reader = new FileReader();
        reader.readAsDataURL(blob);
        reader.onload = function(){
            callback.call(this, reader.result); 
        };
        /**
         * base64 转换到 file
         * 得到一个file文件 类引用下面得,此处以图片为例
         * 此处多此一举 脱裤子放屁
         */
        var file = dataURLtoFile(base64, fileName);
        formData.append(fileName, file);
    }
  }
  xhr.send();
}
getBase64("<https://fastmarket.oss-cn-shenzhen.aliyuncs.com/oss/static/other/1/images/baseMap_index.jpg>",function(data){
    console.log(data)
})//链接是你的网络图片

参考文章:

  1. Blob - Web API 接口参考 | MDN (mozilla.org)
  2. FileReader.readAsArrayBuffer() - Web API 接口参考 | MDN (mozilla.org)
  3. js上传文件file各种类型之间的转换-Mr.Tang的博客 (no-if.com)