Skip to content

文件(File)实现技术 ​

重要通知

类目简介

基本概况 ​

文件格式 ​

云点播支持上传以下类型的媒体文件: 视频:WMV、RM、MOV、MPEG、MP4、3GP、FLV、AVI、RMVB、TS、ASF、MPG、WEBM、MKV 、M3U8、WM、ASX、RAM、MPE、VOB、DAT、MP4V、M4V、F4V、MXF、QT、OGG。 音频:MP3、M4A、FLAC、OGG、WAV、RA、AAC、AMR。 图片:JPG、JPEG、PNG、GIF、BMP、TIFF、AI、CDR、EPS、TIF、HEIF。

上传文件案例 ​

前台文件 ​

<button type="button" id="uploadFile">上传文件</button>


<script type="text/javascript">
  function getFileDataUtil(file) {
    return new Promise((resolve) => {
      file.onchange = async function (e) {
        resolve(e.target.files[0]);
      };
    });
  }

  // fetch上传
  async function uploadFileByFetch(formData) {
    const result = await fetchAPI({
      path: "https://api.ysunlight.com/api/upload/file-single?label=1&name=eshen",
      method: "post",
      data: formData,
      uploadType: "file",
    })
      .then((res) => res)
      .catch((err) => err);

    console.info("上传文件:", result);
  }
</script>

<script type="text/javascript">
  var uploadFileEl = document.querySelector("#uploadFile");

  uploadFileEl.onclick = async function () {
    const file = document.createElement("input");
    file.setAttribute("type", "file");
    file.click();

    const fileData = await getFileDataUtil(file);
    console.info("File对象", fileData);

    const formData = new FormData();
    formData.append("file", fileData);




    uploadFileByFetch(formData);

    fetch("https://api.ysunlight.com/api/get")
      .then((res) => {
        console.log("上传成功: ", res);
      })
      .catch((err) => null);







    // 原生方法
    fetch("https://api.ysunlight.com/api/upload/file-single?name=eshen", {
      method: "POST",
      body: formData,
    })
      .then((res) => {
        console.log("上传成功: ", res);
      })
      .catch((err) => null);
  };
</script>

后台文件 ​

const fs = require("fs");


// https://api.ysunlight.com/api/upload/file-single
router.post("/api/upload/file-single", koaBody({
  multipart: true,
  encoding: 'gzip',
  formidable: {
    multipart: true,
    keepExtensions: true,
    maxFileSize: 10 * 1024 * 1024 * 1024  //10G
  }
}), async (ctx) => {
  let resdt = { status: 200, msg: "success", data: {} };

  const query = ctx.request.query;
  const method = ctx.request.method;
  const header = ctx.request.header;
  const url = ctx.request.url;
  const body = ctx.request.body;

  console.log("query: ", query);
  console.log("method: ", method);
  console.log("header: ", header);
  console.log("url: ", url);
  console.log("body: ", body);

  // 接收文件
  const fileData = ctx.request.files?.file || {};
  console.log("fileData: ", fileData);
  console.log("fileName: ", fileData?.originalFilename);
  console.log("mimetype: ", fileData?.mimetype);
  console.log("size: ", fileData?.size);

  resdt.data['fileurl'] = await saveFile(fileData);

  ctx.body = resdt;
  process.stdout.write(`${JSON.stringify(resdt)}\n\n`);
});

上传文件 ​

<button type="button">上传文件</button>


<script type="text/javascript">
  const button = document.querySelector("button");
  button.addEventListener("click", uploadAction, false);

  async function uploadAction() {
    const fileEl = document.createElement("input");
    if (!fileEl) return;

    fileEl.setAttribute("type", "file");
    fileEl.setAttribute("name", "input-file");
    fileEl.setAttribute("multiple", "multiple");
    fileEl.setAttribute("accept", "image/gif,image/jpeg,image/png");
    fileEl.setAttribute("accept", ".doc,.docx,.xml,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document");

    // accept不传,默认所有文件

    // 任何音频文件
    fileEl.setAttribute("accept", "audio/*");

    // 任何视频文件
    fileEl.setAttribute("accept", "video/*");

    // 任何图片文件
    fileEl.setAttribute("accept", "image/*");

    fileEl.click();

    const getFileData = (fileTarget) => {
      return new Promise((resolve) => {
        fileTarget.onchange = async function (e) {
          resolve(e.target.files[0]);
        };
      });
    };

    const fileData = await getFileData(fileEl);
    console.info("fileData: ", fileData);

    const getReaderData = (fileData) => {
      const reader = new FileReader();
      reader.readAsDataURL(fileData); // 二进制

      return new Promise((resolve) => {
        reader.onload = function () {
          resolve(reader.result);
        };
      });
    };

    const readerData = await getReaderData(fileData);
    console.info("readerData: ", readerData);
  }
</script>

Content-Type 请求类型 ​

# Content-Type 请求类型
  multipart/form-data // FormData
  application/x-www-urlencoded  // 表单
  application/json // json
  application/json-patch+json
  application/vnd.api+json
  application/csp-report
  text/xml
  text/plain


# 包含类型 | application audio font example image message model multipart text video


/**
 * MIME 类型
 * MIME (Multipurpose Internet Mail Extensions) 是描述消息内容类型的因特网标准
 * MIME 消息能包含文本、图像、音频、视频以及其他应用程序专用的数据
 * 
 * Content-Type: 'image/png'
 * Content-Length: data.length
 */

// 按照内容类型排列的 Mime 类型列表
-----------------------------------------------------------------
  类型/子类型	                                 扩展名
-----------------------------------------------------------------
  text/html	                                   htm
  text/html	                                   html
  text/css	                                   css
  text/javascript                              js

  image/gif	                                   gif
  image/jpeg	                                 jpeg
  image/jpeg	                                 jpg
  image/png                                    png

  application/pdf	                             pdf


  application/envoy	                           evy
  application/fractals	                       fif
  application/futuresplash	                   spl
  application/hta	                             hta
  application/internet-property-stream	       acx
  application/mac-binhex40	                   hqx
  application/msword	                         doc
  application/msword	                         dot
  application/octet-stream	                   *
  application/octet-stream	                   bin
  application/octet-stream	                   class
  application/octet-stream	                   dms
  application/octet-stream	                   exe
  application/octet-stream	                   lha
  application/octet-stream	                   lzh
  application/oda	                             oda
  application/olescript	                       axs
  application/pics-rules	                     prf
  application/pkcs10	                         p10
  application/pkix-crl	                       crl
  application/postscript	                     ai
  application/postscript	                     eps
  application/postscript	                     ps
  application/rtf	                             rtf
  application/set-payment-initiation	         setpay
  application/set-registration-initiation	     setreg
  application/vnd.ms-excel	                   xla
  application/vnd.ms-excel	                   xlc
  application/vnd.ms-excel	                   xlm
  application/vnd.ms-excel                   	 xls
  application/vnd.ms-excel	                   xlt
  application/vnd.ms-excel	                   xlw
  application/vnd.ms-outlook	                 msg
  application/vnd.ms-pkicertstore	             sst
  application/vnd.ms-pkiseccat	               cat
  application/vnd.ms-pkistl	                   stl
  application/vnd.ms-powerpoint	               pot
  application/vnd.ms-powerpoint	pps
  application/vnd.ms-powerpoint	ppt
  application/vnd.ms-project	mpp
  application/vnd.ms-works	wcm
  application/vnd.ms-works	wdb
  application/vnd.ms-works	wks
  application/vnd.ms-works	wps
  application/winhlp	hlp
  application/x-bcpio	bcpio
  application/x-cdf	cdf
  application/x-compress	z
  application/x-compressed	tgz
  application/x-cpio	cpio
  application/x-csh	csh
  application/x-director	dcr
  application/x-director	dir
  application/x-director	dxr
  application/x-dvi	dvi
  application/x-gtar	gtar
  application/x-gzip	gz
  application/x-hdf	hdf
  application/x-internet-signup	ins
  application/x-internet-signup	isp
  application/x-iphone	iii
  application/x-javascript	js
  application/x-latex	latex
  application/x-msaccess	mdb
  application/x-mscardfile	crd
  application/x-msclip	clp
  application/x-msdownload	dll
  application/x-msmediaview	m13
  application/x-msmediaview	m14
  application/x-msmediaview	mvb
  application/x-msmetafile	wmf
  application/x-msmoney	mny
  application/x-mspublisher	pub
  application/x-msschedule	scd
  application/x-msterminal	trm
  application/x-mswrite	wri
  application/x-netcdf	cdf
  application/x-netcdf	nc
  application/x-perfmon	pma
  application/x-perfmon	pmc
  application/x-perfmon	pml
  application/x-perfmon	pmr
  application/x-perfmon	pmw
  application/x-pkcs12	p12
  application/x-pkcs12	pfx
  application/x-pkcs7-certificates	p7b
  application/x-pkcs7-certificates	spc
  application/x-pkcs7-certreqresp	p7r
  application/x-pkcs7-mime	p7c
  application/x-pkcs7-mime	p7m
  application/x-pkcs7-signature	p7s
  application/x-sh	sh
  application/x-shar	shar
  application/x-shockwave-flash	swf
  application/x-stuffit	sit
  application/x-sv4cpio	sv4cpio
  application/x-sv4crc	sv4crc
  application/x-tar	tar
  application/x-tcl	tcl
  application/x-tex	tex
  application/x-texinfo	texi
  application/x-texinfo	texinfo
  application/x-troff	roff
  application/x-troff	t
  application/x-troff	tr
  application/x-troff-man	man
  application/x-troff-me	me
  application/x-troff-ms	ms
  application/x-ustar	ustar
  application/x-wais-source	src
  application/x-x509-ca-cert	cer
  application/x-x509-ca-cert	crt
  application/x-x509-ca-cert	der
  application/ynd.ms-pkipko	pko
  application/zip	zip
  audio/basic	au
  audio/basic	snd
  audio/mid	mid
  audio/mid	rmi
  audio/mpeg	mp3
  audio/x-aiff	aif
  audio/x-aiff	aifc
  audio/x-aiff	aiff
  audio/x-mpegurl	m3u
  audio/x-pn-realaudio	ra
  audio/x-pn-realaudio	ram
  audio/x-wav	wav
  
  image/bmp	bmp
  image/cis-cod	cod
  image/ief	ief

  image/pipeg	jfif
  image/svg+xml	svg
  image/tiff	tif
  image/tiff	tiff
  image/x-cmu-raster	ras
  image/x-cmx	cmx
  image/x-icon	ico
  image/x-portable-anymap	pnm
  image/x-portable-bitmap	pbm
  image/x-portable-graymap	pgm
  image/x-portable-pixmap	ppm
  image/x-rgb	rgb
  image/x-xbitmap	xbm
  image/x-xpixmap	xpm
  image/x-xwindowdump	xwd
  message/rfc822	mht
  message/rfc822	mhtml
  message/rfc822	nws
  text/h323	323

  text/html	stm
  text/iuls	uls
  text/plain	bas
  text/plain	c
  text/plain	h
  text/plain	txt
  text/richtext	rtx
  text/scriptlet	sct
  text/tab-separated-values	tsv
  text/webviewhtml	htt
  text/x-component	htc
  text/x-setext	etx
  text/x-vcard	vcf

  video/mpeg	mp2
  video/mpeg	mpa
  video/mpeg	mpe
  video/mpeg	mpeg
  video/mpeg	mpg
  video/mpeg	mpv2
  video/quicktime	mov
  video/quicktime	qt
  video/x-la-asf	lsf
  video/x-la-asf	lsx
  video/x-ms-asf	asf
  video/x-ms-asf	asr
  video/x-ms-asf	asx
  video/x-msvideo	avi
  video/x-sgi-movie	movie

  x-world/x-vrml	flr
  x-world/x-vrml	vrml
  x-world/x-vrml	wrl
  x-world/x-vrml	wrz
  x-world/x-vrml	xaf
  x-world/x-vrml	xof
-----------------------------------------------------------------

ActiveXObject ​

该对象是微软的私有拓展名, 只在微软的IE浏览器上支持,ActiveXObject 启用会返回一个自动化对象的引用,这个对象只能用于实例化自动化对象,它没有任何成员对象。

# 语法
let newObj = new ActiveXObject(servername, typename[, location])  
# 参数
> servername:提供对象的应用程序的名称  
> typename: 要创建的对象的类型或类  
> location: 要创建对象的网络服务器的名称  

# 备注
> servername.typename的值:Excel.Application、Excel.Chart、Scripting.FileSystemObject、WScript.Shell、Word.Document;


# 兼容性支持
> Supported in the following document modes: Quirks, Internet Explorer 6 standards, Internet Explorer 7 standards, Internet Explorer 8 standards, Internet Explorer 9 standards, Internet Explorer 10 standards, Internet Explorer 11 standards.

File对象 ​

File:https://developer.mozilla.org/zh-CN/docs/Web/API/File

File对象数据结构 ​

{
  lastModified: 1713116761687
  lastModifiedDate: Mon Apr 15 2024 01:46:01 GMT+0800 (中国标准时间) {}
  name: "BB1lA8Hk.png"
  size: 524776
  type: "image/png"
  webkitRelativePath: ""
}

File 对象相关属性 ​

File 对象是来自用户在一个 <input> 元素上选择文件后返回的 FileList 对象 File 接口没有定义任何方法, 从 Blob 接口继承了以下方法, 也继承了 Blob 接口的属性

FileList
  File 
    {
      lastModified       // 返回当前 File 对象所引用文件最后修改时间,自 UNIX 时间起始值(1970年1月1日 00:00:00 UTC)以来的毫秒数
      lastModifiedDate   // 返回当前 File 对象所引用文件最后修改时间的 Date 对象。
      name               // 返回当前 File 对象所引用文件的名字
      size               // 返回文件的大小
      type               // 返回文件的 多用途互联网邮件扩展类型(MIME Type)
      webkitRelativePath // 返回 File 相关的 path 或 URL。
    }

// 结构语法
const file = new File(
  bits, // 一个包含ArrayBuffer,ArrayBufferView,Blob,或者 DOMString 对象的 Array — 或者任何这些对象的组合。这是 UTF-8 编码的文件内容。
  name, // USVString,表示文件名称,或者文件路径。
  options // 选项对象,包含文件的可选属性。type: DOMString,表示将要放到文件中的内容的 MIME 类型。默认值为 "" ,见WEB/AJAX/[Content-Type媒体类型与MIME 类型].md。lastModified: 数值,表示文件最后修改时间的 Unix 时间戳(毫秒)。默认值为 Date.now()。
);

File 对象相关方法 ​

Blob.slice

Blob.slice(
  start:        // 这个参数代表 Blob 里的下标,表示第一个会被会被拷贝进新的 Blob 的字节的起始位置。
  end:          // 这个参数代表的是 Blob 的一个下标,这个下标-1的对应的字节将会是被拷贝进新的Blob 的最后一个字节。
  contentType:  // 给新的 Blob 赋予一个新的文档类型。这将会把它的 type 属性设为被传入的值。它的默认值是一个空的字符串。
);

const path = URL.createObjectURL(blob);
URL.revokeObjectURL(path);

FileReader ​

​

​

https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader

FileReader ​

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

FileReader属性 ​

const reader = new FileReader();

reader.readyState
reader.result

// 异步
const getDataText = (content) => {
  const reader = new FileReader();
  reader.readAsText(content, 'utf-8');

  return new Promise((resolve) => {
    reader.onload = function() {
      resolve(reader.result);
    }
  });
}
const dataText = await getDataText(textBlob);

FileReader事件 ​

const reader = new FileReader();

//解析文件开始
reader.onloadstart = function(e) {
  console.log(e);
}     

//解析文件进度
reader.onprogress = function(e) {
  console.log(e);
} 

//解析文件中断
reader.onabort = function(e) {
  console.log(e);
}

//解析文件错误
reader.onerror = function(e) {
  console.log(e);
}

//解析文件完成
reader.onload = function(e) {
  const result = e.target.result || this.result;
  console.log(e);
  img.src = result;
  //这样就获取到了文件的Base64字符串
  //var base64 = getBase64Image(image);
  //Base64字符串转二进制
  //var file = dataURLtoBlob(base64);

  //上传
  var blob = new Blob([result], { type: 'image/jpg' });
  var fd = new FormData();
  fd.append('file', blob);

  //提交到服务器, 见ajax
}

//解析文件结束
reader.onloadend = function(e) {
  console.log(e);
}

FileReader接口 ​

const file = file.files[0];
const reader = new FileReader();

// 注意:需要在reader.onload中读取,因为内容才能保障解析完成

//读取为文本  readAsText(File|Blob [, encoding])    encoding:asni, utf-8, gbk2312, gb2312, binary
// reader.readAsText(file, 'gb2312');

//将文件读取为 二进制码  readAsBinaryString(File|Blob), 从 2012 年 7 月 12 日起,该方法已从 W3C 工作草案废除。
reader.readAsBinaryString(file);

//将文件读取为 DataURL  readAsDataURL(File|Blob)
reader.readAsDataURL(file);

//将文件读取为 缓冲区  readAsArrayBuffer(File|Blob)
reader.readAsArrayBuffer(file);

FileReaderSync ​

FileReaderSync接口允许以同步的方式读取File或Blob对象中的内容,该接口只在workers里可用,因为在主线程里进行同步I/O操作可能会阻塞用户界面。

​

​

https://developer.mozilla.org/zh-CN/docs/Web/API/FileReaderSync

​

​

基本类型 MIME-type ​

# -----------------------------------------------------------------------------------
	文件后缀       MIME-type
# -----------------------------------------------------------------------------------
	*.3gpp        audio/3gpp, video/3gpp
	*.ac3         audio/ac3
	*.asf         allpication/vnd.ms-asf
	*.au          audio/basic
	*.css         text/css
	*.csv         text/csv
	*.doc    			application/msword    
	*.dot    			application/msword    
	*.dtd    			application/xml-dtd    
	*.dwg    			image/vnd.dwg    
	*.dxf      		image/vnd.dxf
	*.gif         image/gif    
	*.htm    			text/html    
	*.html    		text/html    
	*.jp2         image/jp2    
	*.jpe       	image/jpeg
	*.jpeg    		image/jpeg
	*.jpg         image/jpeg    
	*.js       		text/javascript, application/javascript    
	*.json    		application/json    
	*.mp2    			audio/mpeg, video/mpeg    
	*.mp3    			audio/mpeg    
	*.mp4    			audio/mp4, video/mp4    
	*.mpeg    		video/mpeg    
	*.mpg    			video/mpeg    
	*.mpp    			application/vnd.ms-project    
	*.ogg    			application/ogg, audio/ogg    
	*.pdf    			application/pdf    
	*.png    			image/png    
	*.pot    			application/vnd.ms-powerpoint    
	*.pps    			application/vnd.ms-powerpoint    
	*.ppt    			application/vnd.ms-powerpoint    
	*.rtf         application/rtf, text/rtf    
	*.svf         image/vnd.svf    
	*.tif         image/tiff    
	*.tiff       	image/tiff    
	*.txt         text/plain    
	*.wdb    			application/vnd.ms-works    
	*.wps    			application/vnd.ms-works    
	*.xhtml    		application/xhtml+xml    
	*.xlc      		application/vnd.ms-excel    
	*.xlm    			application/vnd.ms-excel    
	*.xls         application/vnd.ms-excel    
	*.xlt      		application/vnd.ms-excel    
	*.xlw     		application/vnd.ms-excel    
	*.xml    			text/xml, application/xml    
	*.zip         application/zip    
	*.xlsx     		application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
# -----------------------------------------------------------------------------------

支持的文件类型 ​

支持 doc, docx, xls, xlsx, xlsm, ppt, pptx, csv, tsv, dotm, xlt, xltm, dot, dotx,xlam, xla 等 Office 办公文档 支持 wps, dps, et, ett, wpt 等国产 WPS Office 办公文档 支持 odt, ods, ots, odp, otp, six, ott, fodt, fods 等OpenOffice、LibreOffice 办公文档 支持 vsd, vsdx 等 Visio 流程图文件 支持 wmf, emf 等 Windows 系统图像文件 支持 psd 等 Photoshop 软件模型文件 支持 pdf ,ofd, rtf 等文档 支持 xmind 软件模型文件 支持 bpmn 工作流文件 支持 eml 邮件文件 支持 epub 图书文档 支持 obj, 3ds, stl, ply, gltf, glb, off, 3dm, fbx, dae, wrl, 3mf, ifc, brep, step, iges, fcstd, bim 等 3D 模型文件 支持 dwg, dxf 等 CAD 模型文件 支持 txt, xml(渲染), md(渲染), java, php, py, js, css 等所有纯文本 支持 zip, rar, jar, tar, gzip, 7z 等压缩包 支持 jpg, jpeg, png, gif, bmp, ico, jfif, webp 等图片预览(翻转,缩放,镜像) 支持 tif, tiff 图信息模型文件 支持 tga 图像格式文件 支持 svg 矢量图像格式文件 支持 mp3,wav,mp4,flv 等音视频格式文件 支持 avi,mov,rm,webm,ts,rm,mkv,mpeg,ogg,mpg,rmvb,wmv,3gp,ts,swf 等视频格式转码预览

二进制文件(.bin)

二进制文件,格式binary的缩写,例如main.bin。

数据结构之间转换 ​

​

Blob转File对象 ​

  this.modal.data = URL.createObjectURL(data);
  this.modal.visual = false;

  // 转换函数
  const file = new window.File([data], this.file.name)

  let formData = new FormData();
  formData.append("content", file);

URL转Base64 ​

URL转Blob ​

Base64转Blob ​

Blob转Base64 ​

网络图像文件转Base64 ​

function getBase64Image(img) {
  var canvas = document.createElement("canvas");
  canvas.width = img.width;
  canvas.height = img.height;
  var ctx = canvas.getContext("2d");
  ctx.drawImage(img, 0, 0, img.width, img.height);
  var ext = img.src.substring(img.src.lastIndexOf(".") + 1).toLowerCase();
  var dataURL = canvas.toDataURL("image/" + ext);
  return dataURL;
};

Base64字符串转二进制 ​

见腾讯云COS上传示例。

function dataURItoBlobUtil(base64: string) {
  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 Blob([u8arr], {
    type: mime
  });
};

Base64字符串转二进制 ​

dataURItoBlobUtil(dataURI) {
  // base64 解码
  let byteString = window.atob(dataURI.split(',')[1])
  let mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]
  let ab = new ArrayBuffer(byteString.length)
  let ia = new Uint8Array(ab)
  for (let i = 0; i < byteString.length; i++) {
    ia[i] = byteString.charCodeAt(i)
  }
  return new Blob([ab], {type: mimeString})
}

Blob | 使用 Blob 创建一个指向类型化数组的URL ​

后端返回blob数据:服务端返回的为资源的二进制数据 前端处理: 前端接收到二进制数据后,使用 URL.createObjectURL(blobData) 方法将服务端返回的二进制数据转换为 blob 的 url 资源挂载到相应的资源对象。

  var typedArray = GetTheTypedArraySomehow();
  var blob = new Blob([typedArray.buffer], {type: 'application/octet-stream'}); // 传入一个合适的 MIME 类型
  var url = URL.createObjectURL(blob);

利用canvas.toDataURL的API转化成base64 ​

function base64ToBlob ({b64data = '', contentType = '', sliceSize = 512} = {}) {
  return new Promise((resolve, reject) => {
    // 使用 atob() 方法将数据解码
    let byteCharacters = atob(b64data);
    let byteArrays = [];
    for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
      let slice = byteCharacters.slice(offset, offset + sliceSize);
      let byteNumbers = [];
      for (let i = 0; i < slice.length; i++) {
          byteNumbers.push(slice.charCodeAt(i));
      }
      // 8 位无符号整数值的类型化数组。内容将初始化为 0。
      // 如果无法分配请求数目的字节,则将引发异常。
      byteArrays.push(new Uint8Array(byteNumbers));
    }
    let result = new Blob(byteArrays, {
      type: contentType
    })
    result = Object.assign(result,{
      // 这里一定要处理一下 URL.createObjectURL
      preview: URL.createObjectURL(result),
      name: `XXX.png`
    });
    resolve(result)
  })
 }

字符串与Blob转换 ​

  // 字符串转换为Blob
  const text = "你好,我是字符串";
  const textBlob = new Blob([text],{type: 'text/plain'});
  console.info(textBlob);

  // Blob转换为字符串
  const getDataText = (content) => {
    const reader = new FileReader();
    reader.readAsText(content, 'utf-8');

    return new Promise((resolve) => {
      reader.onload = function() {
        resolve(reader.result);
      }
    });
  }
  const dataText = await getDataText(textBlob);

File对象与Blob对象转换 ​

    document.getElementById('uploadFile').onclick = function() {
      const file = document.createElement('input');
      file.setAttribute('type', 'file');
      // file.setAttribute('accept', 'video/mp4,video/webm,video/ogg');
      file.click();

      const getFileData = (file) => {
        return new Promise((resolve) => {
          file.onchange = async function(e) {
            resolve(e.target.files[0]);
          }
        });
      }

      const fileData = await getFileData(file);
      console.info('File对象', fileData);

      // File转换为Blob
      const fileBlob = new Blob([fileData], {type: fileData.type});
      console.info(fileBlob); 

      // Blob转换为File
      const fileData = new File([fileBlob], file.name, {type: file.type});
      console.info(fileData);


      // 上传文件
      const formData = new FormData();
      formData.append('file', fileData);

    }

Base64编码 ​

数据结构 ​

  • 图片
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAwAAAAGlCAYAAABNz5H6AAAACXBIWXMAAA7EAAAOxAGVKw4bAAD//0lEQVR4Aey96ZMk23Hll91dvb0VwBDEQpg4w23MJJNJJpP0Rf//R0lfRiMNiY0gsRHkYIiH13t16/yO3xPhERmRmVVd/fAw0u2uuH59d79L7JFX3//v/7d3n3z09PDx06eHq/v3D/cO7w737t07vH331vC7t9SHw713wuvf2+u3alV5K9pb8b958+ZwEP+Dq4eiXx/+9b/8l8O/fvHFQSKHg3RSAF3uyYb+Hj16dPj4k08PTx49cf.....此处省略大量字符串.....AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
  • 音频
data:audio/mpeg;base64,SUQzAgAAAAAPdlRDTQAACwH//i6WSU5/YgAAVFQxAAAdAf/+ZGvGiZGYCWdzUUYANQDzl1BOIAAyADEAAABUVDIAABMB//5GADUA85dQTiAAMgAxAAAAVEVOAAAhAFByb1RyYW5zY29kZXJUb29sIChBcHBsZSBNUDMgdjEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.....此处省略大量字符串.....AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==

​

Base64的编码与解码:https://developer.mozilla.org/zh-CN/docs/Glossary/Base64#Appendix.3A_Decode_a_Base64_string_to_Uint8Array_or_ArrayBuffer

简介与核心思想 ​

Base64就是一种基于64个可打印字符来表示二进制数据的方法。

解码和编码 base64 字符串 ​

如果传入字符串不是有效的 base64 字符串,比如其长度不是 4 的倍数,则抛出DOMException。

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

// 解码
let decodedData = window.atob(encodedData);

Blob ​

注意 ​

File、FileList、FileReader、FileReaderSync继承了Blob, 所以Blob的属性与方法也可以在这些对象中使用。

简介与核心思想 ​

Blob() 构造函数返回一个新的 Blob 对象。 blob的内容由参数数组中给出的值的串联组成。

语法 ​

  new Blob( 
    array,                      // array 是一个由ArrayBuffer, ArrayBufferView, Blob, DOMString 等对象构成的 Array ,或者其他类似对象的混合体,它将会被放进 Blob。DOMStrings会被编码为UTF-8
    options: {                  // options 是一个可选的BlobPropertyBag字典,它可能会指定如下两个属性, {}
      type: '',                 // type,默认值为 "",它代表了将会被放入到blob中的数组内容的MIME类型。
      endings: 'transparent'    // endings,默认值为"transparent",用于指定包含行结束符\n的字符串如何被写入。 它是以下两个值中的一个: "native",代表行结束符会被更改为适合宿主操作系统文件系统的换行符,或者 "transparent",代表会保持blob中保存的结束符不变
    }
  );

Blob属性 ​

Blob.size:Blob 对象中所包含数据的大小(字节)。 Blob.type:一个字符串,表明该 Blob 对象所包含数据的 MIME 类型。如果类型未知,则该值为空字符串。

Blob方法 ​

Blob.slice([start[, end[, contentType]]]):返回一个新的 Blob 对象,包含了源 Blob 对象中指定范围内的数据。 Blob.stream():返回一个能读取blob内容的 ReadableStream。 Blob.text():返回一个promise且包含blob所有内容的UTF-8格式的 USVString。 Blob.arrayBuffer():返回一个promise且包含blob所有内容的二进制格式的 ArrayBuffer

从Blob中读取数据 ​

  // 方法一:一种从Blob中读取内容的方法是使用 FileReader。
  var reader = new FileReader();
  reader.addEventListener("loadend", function() {
    // reader.result 包含被转化为类型数组 typed array 的 blob
  });
  reader.readAsArrayBuffer(blob);


  // 方法二:另一种读取Blob中内容的方式是使用Response对象。
  var text = await (new Response(blob)).text();

代码示例 ​

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

  var aFileParts = ['<a id="a"><b id="b">hey!</b></a>']; // 一个包含DOMString的数组
  var oMyBlob = new Blob(aFileParts, {type : 'text/html'}); // 得到 blob


  let typedArrayToURL = (typedArray, mimeType) => {
    return URL.createObjectURL(new Blob([typedArray.buffer], {type: mimeType}))
    // 产生一个类似 blob:d3958f5c-0777-0845-9dcf-2cb28783acaf 这样的URL字符串
  }

  let bytes = new Uint8Array(59);

  for (let i=0; i<59; i++) {
    bytes[i] = 32+i;
  }

  let url = typedArrayToURL(bytes, "text/plain");
  let link = document.createElement("a");
  link.href = url;
  link.innerText = "Open the array URL";
  document.body.appendChild(link);
html
<input type="file" id="single" onchange="singleFile()">
/**
 * 大文件分片上传技术
 *
 */
//兼容性支持
function blobSlice(blob) {
  let blobSlice = blob;
  if (blob.mozSlice) {  //Firefox 12及更早版本
    blobSlice = blob.mozSlice;
  } 
  if (blob.webkitSlice) {  //Safari旧版本
    blobSlice = blob.webkitSlice;
  }
  //其他
  blobSlice = blob.slice;

  //分片技术
  return blobSlice;
}

//分片上传
function Burst() {
  //
}





let file = document.getElementsByTagName('input')[0];
function singleFile() {
  let content = file.files[0];
  let size = content.size;  //name、size、type、lastModified
  console.log('文件分片前大小: ' + size);

  let scale = 100 * 1024;
  //小于scale,则不分片
  if (size > scale) {
    //
  }
  let multiple = Math.ceil(size / scale);
  console.log('分片数量:' + multiple);
  let remainder = size % scale;

  //没有余数,全是倍数
  if (remainder == 0) {
    //
  }

  let integer = scale * (multiple - 1);
  let total = integer + remainder;
  console.log('分片合并后大小:' + total);

  //整合分片数据结构
  let sliceData = [];
  for (let i = 0; i < multiple; i++) {
    (function(i) {
      let slice = {};
      slice['type'] = content.type;
      slice['name'] = content.name;
      slice['lastModified'] = content.lastModified;
      slice['total'] = content.size;
      slice['id'] = i;
      slice['prev'] = i*scale;
      slice['next'] = (i+1)*scale;
      slice['blob'] = content.slice(i*scale, (i+1)*scale);
      slice['size'] = scale;
      //兼容分片不足整数部分
      if (i == multiple - 1) {
        let last = i*scale + remainder;
        slice['next'] = last;
        slice['blob'] = content.slice(i*scale, last);
        slice['size'] = remainder;
      } 
      
      sliceData.push(slice);
    })(i);
  }
  
  recurrence(sliceData);
  //decollate(sliceData);

}

//分割上传-递归等待分片上传成功
function recurrence(sliceData) {
  sliceData = sliceData || [];

  //递归推送, 成功继续推送
  let count = 0;
  function pushBlob(i) {
    //推送完成
    if (count == sliceData.length) {
      return ;
    }

    let dx = sliceData[i];

    //封装数据
    let formData = new FormData();
    formData.append("content", dx.blob);

    //拼接片段标志参数
    let query = "";
    for (let i in dx) {
      if (i != 'blob') {
        query += '&' + i + '=' + dx[i];
      }
    }
    query = query.replace(/^&/, '?');

    //开始推送
    ajax({ 
      base: 'http://127.0.0.1:7901/',
      path: 'decollate' + query,
      method: 'post',
      type: 'upload',
      timeout: 1500000,
      size: dx.size,
      data: formData,
      complete() {},
      success(res) {
        //继续推送下一流
        count += 1;
        pushBlob(count);
      },
      fail(err) {
        //推送失败,重复推送
        pushBlob(count);
      }
    });

  }
  pushBlob(count);

}

//分割上传-演示
function decollate(sliceData) {
  sliceData = sliceData || [];

  sliceData.forEach((dx)=> {
    let formData = new FormData();
    formData.append("content", dx.blob);

    //拼接片段标志参数
    let query = "";
    for (let i in dx) {
      if (i != 'blob') {
        query += '&' + i + '=' + dx[i];
      }
    }
    query = query.replace(/^&/, '?');

    //推送服务器
    ajax({ 
      base: 'http://127.0.0.1:7901/',
      path: 'decollate' + query,
      method: 'post',
      type: 'upload',
      timeout: 1500000,
      size: dx.size,
      data: formData,
      complete() {},
      success(res) {
        //console.log(res);
      },
      fail(err) {
        //console.log(err);
      }
    });
  });
}

实践运用 ​

断点续传 ​

# 断点续传 • 上传
> 见Blob部分


# 断点续传 • 下载
> 注意Response Headers响应头的几个字段
# 告诉服务器从什么字节开始,而不是全部下载
Range: bytes=2000070-

# 完整
Range: bytes=startOffset-targetOffset/sum  [表示从startOffset读取,一直读取到targetOffset位置,读取总数为sum直接]
Range: bytes=startOffset-targetOffset  [字节总数也可以去掉]

# 服务器响应
HTTP/1.1 206 Partial Content
Content-Range=bytes 2000070-106786027/106786028

下载文件 ​

下载单一文件 ​

document.getElementById("singleDownload").addEventListener(
  "click",
  () => {
    let a = document.createElement("a");
    let url = "http://test.ysunlight.com/static/images/345.jpeg";
    a.setAttribute("download", "test.jpg");
    a.href = url;

    a.click();
    a.remove();
  },
  false,
);

// 下载图片
async function downloadImage(image) {
  const link = URL.createObjectURL(image);

  const a = document.createElement("a");
  a.download = "activity-share-" + Date.now() + ".png";
  a.href = link;

  var fileInput = document.createElement("input");
  fileInput.type = "file";
  fileInput.style.display = "none";
  fileInput.webkitdirectory = link;
  document.body.appendChild(fileInput);

  a.click();
  a.remove();
  document.body.removeChild(fileInput);
  window.URL.revokeObjectURL(link);
}

批量下载文件 ​

<!doctype html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Axios | 批量下载</title>
    <link
      rel="stylesheet"
      href="http://test.ysunlight.com/public/style/default.css"
    />
    <link
      rel="stylesheet"
      href="http://test.ysunlight.com/public/style/public.css"
    />
    <style type="text/css">
      ul > li {
        float: left;
      }
    </style>
  </head>
  <body data-url="http://test.ysunlight.com/WEB/ajax/批量下载.html">
    <div>
      <p>http://test.ysunlight.com/Reference/images/111.jpg</p>
      <p>http://test.ysunlight.com/Reference/images/141_1443.jpg</p>
      <button onclick="downloadImage()" type="button">批量打包下载</button>
    </div>

    <div>
      <p>http://test.ysunlight.com/Reference/document/doc/常用资料 (1).doc</p>
      <p>http://test.ysunlight.com/Reference/document/doc/常用资料 (2).doc</p>
      <button onclick="downloadFile" type="button">批量打包下载</button>
    </div>
  </body>
  <script src="http://test.ysunlight.com/WEB/ajax/axios/source/axios.min.js"></script>
  <script src="http://test.ysunlight.com/WEB/ajax/jszip/dist/jszip.min.js"></script>
  <script src="http://test.ysunlight.com/WEB/ajax/file-saver/dist/FileSaver.min.js"></script>
  <script type="module">
    import {
      GET,
      POST,
      UPLOAD,
      DOWNLOAD,
    } from "http://test.ysunlight.com/WEB/ajax/axios/axios.api.js";
    import { GenerateImageData } from "/public/module/image.js";
    import { ImageCanvasBase64 } from "/public/module/imageCanvasBase64.js";

    // 批量下载图片
    // const imageArray = [
    //   'http://test.ysunlight.com/Reference/images/111.jpg',
    //   'http://test.ysunlight.com/Reference/images/141_1443.jpg'
    // ];
    const imageArray = [
      "http://test.ysunlight.com/Reference/document/doc/常用资料 (1).doc",
      "http://test.ysunlight.com/Reference/document/doc/常用资料 (2).doc",
    ];

    function download(url) {
      return new Promise((resolve, reject) => {
        DOWNLOAD(url)
          .then((res) => {
            resolve(res);
          })
          .catch(() => {
            reject(null);
          });
      });
    }

    // 批量下载文件
    async function downloadFile() {
      var zip = new JSZip();

      for (let i = 0; i < imageArray.length; i++) {
        const file = imageArray[i]
          .split("/")
          [imageArray[i].split("/").length - 1].split("?")[0];
        const result = await download(imageArray[i]);

        zip.file(file, result, { binary: true });
        console.log(result);
      }

      zip.generateAsync({ type: "blob" }).then(function (content) {
        saveAs(content, `${Date.now()}.zip`);
      });
    }

    // 批量下载图片
    async function downloadImage() {
      var zip = new JSZip();

      for (let i = 0; i < imageArray.length; i++) {
        const { image } = await GenerateImageData(imageArray[i]);
        if (!image) return;
        const imageDt = await ImageCanvasBase64(image);
        const file = imageArray[i]
          .split("/")
          [imageArray[i].split("/").length - 1].split("?")[0];

        zip.file(file, imageDt.split(",")[1], { base64: true });
      }

      zip.generateAsync({ type: "blob" }).then(function (content) {
        saveAs(content, `${Date.now()}.zip`);
      });
    }
  </script>
</html>

Released under the MIT License.