前端文件操作

浏览器由于安全性要求,不允许JS直接获取主机的文件系统上的文件,只能通过HTML标签input[type=file]来由用户选择可以被浏览器操作的文件。

那么input[type=file]标签选择的文件,会被如何保存呢?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
 
<body>
	<input type="file"/>
</body>
</html>

发现打印的DOM元素对象input中有一个特殊的属性files

 files属性的类型是FileList,从名字就可以看出它是一个类数组,类数组元素是File类型对象

那么如果input[type=file]标签选择多个文件(标签加一个multiple属性),它的files中应该会包含多个File对象元素

而从打印结果可以看出File类型对象就是我们选择的文件

 

File是啥
File - Web API 接口参考 | MDN (mozilla.org)

MDN关于File的介绍:

作用:

文件(File)接口提供有关文件的信息,并允许网页中的 JavaScript 访问其内容。

如何产生File对象:

通常情况下, File 对象是来自用户在一个 <input> 元素上选择文件后返回的 FileList 对象,也可以是来自由拖放操作生成的 DataTransfer 对象,或者来自 HTMLCanvasElement 上的 mozGetAsFile() API。

File对象的属性

 

lastModified    只读。返回当前 File 对象所引用文件最后修改时间的毫秒数。
lastModifiedDate    只读。返回当前 File 对象所引用文件最后修改时间的 Date 对象。(废弃)
name    只读。返回当前 File 对象所引用文件的名字。
size    只读。返回当前 File 对象所引用文件的大小。
type    只读。返回当前 File 对象所引用文件的MIME类型
webkitRelativePath    只读。返回 File 相关的 path 或 URL。(不推荐)
其中lastModifiedDate,webkitRelativePath不推荐使用

剩下的属性也比较好理解,都是文件常见的信息,比如文件名,文件类型,文件大小,文件最后修改时间,需要注意这些File对象属性都是只读的。

File对象的方法

File对象没有定义任何方法,它的方法都继承自Blob。

 原型链如下

 

可以发现File实例对象可以沿着原型链访问到Blob.prototype上的方法。 

Blob是什么
Blob - Web API 接口参考 | MDN (mozilla.org)

MDN对于Blob介绍是:Blob 对象表示一个不可变、原始数据的类文件对象。

啥叫类文件对象?

Blob翻译过来是 Binary Larger Object,即二进制大对象。即Blob对象的组成是二进制数据。

而我们知道文件也是二进制编码的数据。

那么为什么Blob叫类文件呢,而不是文件呢?

其实Blob在这里代表的是比文件更加底层的概念。

我们知道文件是由二进制数据组成的,那么我们随意编写一些二进制数据,它能代表一个文件吗?答案是不能。文件的二进制数据具有各种特殊标识,来帮助外部理解一堆二进制数据是一个文件。

Blob代表的其实就是文件的切片。

我们知道文件的二进制数据组合在一起才能代表文件,而文件的二进制数据被分段后,比如分成十段,那么每一段都无法表示文件。但是每一段又都是文件的必不可少的组成部分。

此时就需要Blob来表示这些文件切片。所以说Blob是一个类文件对象。它不是文件,但是却和文件有千丝万缕的关系。

在浏览器API中,Blob是File的父类,这很好理解,父类是基类,子类是扩展类,我们可以说文件File是一堆二进制数据,是一个特殊的Blob,它可以当成Blob。但是它又比Blob多了一层含义。

Blob对象的属性:

 

size    只读。Blob 对象中所包含数据的大小(字节)。
type    只读。一个字符串,表明该 Blob 对象所包含数据的 MIME 类型。如果类型未知,则该值为空字符串。
有人说Blob对象咋还有文件才有的MIME类型呢?它不就是一个二进制数据对象吗?

还是要再说明一下,Blob对象相当于File对象的切片,如何标识一个文件切片属于什么文件类型是有必要的,它涉及都二进制数据的解析。

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(blobParts[, options])

返回一个新创建的 Blob 对象,其内容由参数中给定的数组串联组成。

其中blobParts参数是一个数组,数组中的每一项元素连接起来构成Blob对象的数据,数组中的每项元素可以是ArrayBuffer, ArrayBufferView, Blob, DOMString 。

options:可选项,字典格式类型,可以指定如下两个属性:

type,默认值为 "",它代表了将会被放入到blob中的数组内容的MIME类型。
endings,默认值为"transparent",用于指定包含行结束符\n的字符串如何被写入。 它是以下两个值中的一个: "native",表示行结束符会被更改为适合宿主操作系统文件系统的换行符; "transparent",表示会保持blob中保存的结束符不变。
File,Blob的slice方法
那么现在了解Blob,而File继承了Blob的所有方法,且进行了拓展,可以直接操作文件,比如文件分片slice

从打印结果可以看出,file经过slice得到文件切片file_cp,而file_cp就不再是File类型了,而是Blob类型。

File,Blob的text方法
 file.text()返回一个promise,该promise对象的结果是 blob所有内容的UTF-8格式的 USVString。

即file.text()将二进制编码的数据 转成了 utf-8编码的文本字符串。

不知道意义何在.....,就像你用Notepad++打开一张png格式的图片一样。

File,Blob的arrayBuffer方法
file.arrayBuffer()

 file.arrayBuffer()返回一个promise对象,其结果是 blob所有内容的二进制格式的 ArrayBuffer 

ArrayBuffer是啥 


那么啥是ArrayBuffer呢?ArrayBuffer - JavaScript | MDN (mozilla.org)

ArrayBuffer 对象用来表示通用的、固定长度的原始二进制数据缓冲区。

它是一个字节数组,通常在其他语言中称为“byte array”。

你不能直接操作 ArrayBuffer 的内容,而是要通过 TypeArray 或 DataView 对象来操作,它们会将缓冲区中的数据表示为特定的格式,并通过这些格式来读写缓冲区的内容。

为什么ArrayBuffer中的数据无法直接操作呢?

因为ArrayBuffer数组的元素都是字节,即八位二进制数,且是二进制编码的,我们无法将ArrayBuffer字节数组的字节元素取出来,也无法覆盖字节元素。因为我们输入的都是字符,而不是字节。

而我们知道八位二进制数 可以转成 其他类型数据,最常见就是十进制数值,而我们是可以输入十进制数值的,所以可以将ArrayBuffer字节数组转为TypeArray类型数组,常见的TypeArray数组有:

 由于ArrayBuffer都是字节元素,即每个元素都是无符号8位2进制,所以我们通常是将ArrayBuffer转为Unit8Array来进行处理

 此时我们就可以对字节数组转成的Uint8Array数组进行元素操作了

 对Uint8Array修改完后,再将其转为ArrayBuffer,则很简单,Uint8Array对象上就有一个buffer属性,可以获取到之前的ArrayBuffer实例

 另外TypeArray没有新增,删除元素的操作,因为TypeArray的数组长度是固定的,无法改变的。

 所以这么一看ArrayBuffer除了可以转为TypeArray修改字节元素外,也没啥,关键谁没事改字节数啊,文件的字节被改了,可能都无法解析了。

File,Blob的stream方法
file.stream()

返回一个能读取blob内容的 ReadableStream。

那么什么是ReadableStream呢?ReadableStream - Web API 接口参考 | MDN (mozilla.org)

流操作API 中的ReadableStream 接口呈现了一个可读取的二进制流操作。

啥叫二进制流?
我们知道程序上的各种数据在计算机底层上都是二进制形式的,而程序中可识别数据互相传递,就意味着二进制形式数据的传输,即一串010101在各个程序中传输,而这些传输都是有方向性,就像水流一样,总是朝着一个方向流动,不可能出现一股水流出现两个方向。所以二进制数据的传输也是如此,所以二进制数据传输,也叫做流。

那么流的方向有哪些呢?

一个程序需要外部传入数据,那就底层的二进制数据就是朝着该程序输入,也叫输入流。

一个程序向外部提供数据,那么底层二进制数据就是朝程序外输出,也叫输出流。

具体判断是输入流,还是输出流的要点是,数据源是谁,如果从数据源读取数据,那么相当于数据源对外输出,就是输出流,如果向数据源写入数据,那么相当于输入流。

所以一个文件的输出流一般和读操作相关,输入流和写操作相关。

另外有一个关于流的概念,那就是流的组成。

我们知道流是指二进制数据的流动,那么流的组成就是二进制数据。但是二进制数据有不同的形式:

比如 0000000000001111111111111100000000000000,和 00000000 00001111 11111111 11000000 00000000

二者二进制数都相同,都表示40位的二进制数,但是第二个按照8位一组,进行了分组。

我们知道 8 bit = 1 Byte,即8位二进制数 相当于一个字节。

所以在传输中的流有了两个概念,比特(bit)流,和字节(Byte)流,字节流就是将比特流按照8位一组进行分组后的二进制数据。

而在字节之上就是字符了,字符指的就是人类可以识别的文字,而字节是计算机可以识别的文字。

人们制定了各种编码方式,将字节组合起来代表一个人类世界的字符。

比较有名的编码有:ASCII码(英语系编码),GBK码(汉语系编码),UTF-8码(世界所有语言编码)

由于英语只有26字母以及一些常用的英语符号,所以ASCII码只需要一个字节(相当于8位二进制数,可以有255种对应关系)就可以代表所有英语系常用字符。

而汉语有成千上万的文字,即使按照偏旁部首进行分类,也有很多,所以GBK字符需要两个字节(相当于16位二进制数,可以有 2^16 - 1 = 65535种对应关系)

而想要表示世界上所有语言,UTF-8的字符需要三个字节(相当于24位二进制数,即2^24-1种对应关系。)

而无论操作系统,还是浏览器,还是程序编写工具,还是记事本,它们都是直接面向人类的,所以他们需要将字节 按照对应编码规则 转化为 字符。

所以字节流  在进行分组,即按照编码规则分组,比如UTF-8编码,将三个字节分为一组,形成字符流。

而无论是比特流,还是字节流,还是字符流,它们都有流向,即可以分为输入流和输出流。

如果是基于文件的读取和写入的话,那么也可以叫做 读取流(输出流) 和 写入流(输入流)。

ReadableStream 是啥
那么ReadableStream 接口呈现了一个可读取的二进制流操作。

其实就是说 以字节流的方式读取文件中二进制数据 的 操作

 ReadableStream的属性

locked    只读。locked 返回这个可读流是否被一个读取器锁定
 ReadableStream对象的方法

cancel    取消读取流,读取方发出一个信号,表示对这束流失去兴趣。可以传入 reason 参数表示取消原因,这个原因将传回给调用方。
getIterator    创建一个异步的 ReadableStream 迭代器并将流锁定于其上。一旦流被锁定,其他读取器将不能读取它,直到它被释放。
getReader    创建一个读取器并将流锁定于其上。一旦流被锁定,其他读取器将不能读取它,直到它被释放。
pipeThrough    提供将当前流管道输出到一个 transform 流或 writable/readable 流对的链式方法。
pipeTo    将当前 ReadableStream 管道输出到给定的 WritableStream (en-US),并返回一个 promise,输出过程成功时返回 fulfilled,在发生错误时返回 rejected。
tee    tee 方法(tee本意是将高尔夫球放置在球座上)tees 了可读流,返回包含两个ReadableStream 实例分支的数组,每个元素接收了相同的传输数据。
看了一下ReadableStream的各种方法,水很深,暂时搁置一下,后面有时间再分析把。

File,Blob,ArrayBuffer小结
以上,我们了解了File,Blob,ArrayBuffer的一些基本概念和功能。

我们知道了File,Blob,ArrayBuffer都是二进制数据对象,

其中File是文件级别二进制对象,Blob和ArrayBuffer都是普通二进制对象

但是Blob相当于File的切片,即文件切片,是类文件二进制对象。File也可以看成一种特殊的Blob。

而Blob只有四个方法 slice,text,arrayBuffer,stream,File也继承了这四个方法,可以对文件对象进行操作。

但是Blob提供的操作都是宏观的,而ArrayBuffer可以提供更加微观的,基于字节的操作。

ArrayBuffer是一个字节数组,数组元素就是字节,相当于八位二进制数,ArrayBuffer本身无法直接对数组元素进行操作,需要转成TypeArray后才能进行字节元素的修改,另外需要注意的是TypeArray一旦初始化就无法改变自身字节数,即ArrayBuffer虽然可以间接的修改数组中的字节元素,但是无法增加和删除字节元素。

File,Blob,ArrayBuffer转换
三者之间有如下转换关系

文件的BASE64编码
当我们通过input[type=file].files[0]获取到用户选择的文件File对象时,前端一般需要将该File对象上传到服务器,我们知道form表单(enctype=multipart/form-data)可以上传File对象,XMLHttpRequest(Content-Type=multipart/form-data;boundary=随机值)也可以上传File对象,这两种方式都是将文件以二进制数据进行传输。那么有没有办法将文件以文本进行传输呢?

我们知道文件除了二进制编码外,还可以base64编码

BASE64是一种编码方式,通常用于把二进制数据编码为可写的字符形式的数据。这是一种可逆的编码方式。

那么如何实现将文件从二进制编码转为BASE64编码呢?这就要靠FileReader了

FileReader
FileReader - Web API 接口参考 | MDN (mozilla.org)

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

FileReader对象可以读取File或Blob中的二进制数据,考虑到文件可能很大,所以读取操作是异步的。

FileReader对象有一个属性readyState,有三个取值

 当FileReader对象读取二进制数据完成后,就会将读取的内容放在自身的result属性上。注意result属性无法同步获取,只能异步获取。

浏览器会监听FileReader对象的readyState属性值的变化,当发生变化时就会触发FileReader对象身上的事件监听处理程序

onloadstart    该事件在读取操作开始时触发
onprogress    该事件在读取Blob时触发
onload    该事件在读取操作完成时触发
onloadend    该事件在读取操作结束时(要么成功,要么失败)触发
另外FileReader对象还考虑了读取过程发生异常时,

onerror    该事件在读取操作发生错误时触发。
另外FileReader对象还可以终止读取,此时FileReader对象可以调用abort()方法,该方法调用后就会触发自身的onabort事件

onabort    当FileReader对象调用了abort()方法后触发
以上就是FileReader异步处理过程。

下面是FileReader读取二进制数据的操作,FileReader对象可以将读取的二进制数据转化为其他类型的数据,这里有三个方法

readAsArrayBuffer    开始读取指定的 Blob中的内容, 一旦完成, result 属性中保存的将是被读取文件的 ArrayBuffer 数据对象.
readAsDataURL    开始读取指定的Blob中的内容。一旦完成,result属性中将包含一个data: URL格式的Base64字符串以表示所读取文件的内容。
readAsText    开始读取指定的Blob中的内容。一旦完成,result属性中将包含一个字符串以表示所读取的文件内容。
样例

以上是准备工作,通过onloadend监听读取的异步结果result

读取file文件的二进制数据,并将读取内容转化为ArrayBuffer字节数组

读取file文件的二进制数据,并将读取内容转化为文本字符串,采用默认的UTF8编码

读取file文件的二进制数据,并将读取内容转化为BASE64编码的字符串

BASE64编码实现了文件可以基于文本字符串来传输。
 

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
web前端文件管理器是一种用于管理和组织网站的文件和资源的工具。它可以通过图形界面提供简单易用的操作,使开发人员能够轻松地浏览、上传、下载、删除和重命名文件,以及创建、编辑和删除文件夹。 该文件管理器通常具有以下功能和特点: 1. 文件浏览:用户可以通过文件管理器浏览整个网站文件结构,包括文件文件夹。 2. 文件上传和下载:用户可以通过文件管理器上传文件到服务器,也可以从服务器下载文件到本地。 3. 文件删除和重命名:用户可以使用文件管理器删除不需要的文件,也可以重命名文件以提高文件的可读性。 4. 文件夹管理:用户可以在网站中创建、编辑和删除文件夹,以组织和管理文件。 5. 文件编辑:某些文件管理器还提供在线文件编辑功能,例如HTML、CSS、JavaScript等。 6. 权限管理:通过文件管理器,用户可以为文件文件夹设置不同的权限,以控制其他用户对文件的访问、编辑和下载。 7. 多语言支持:文件管理器通常支持多种语言,以适应不同用户的需求。 8. 响应式设计:为了适应不同大小的屏幕,文件管理器通常具有响应式设计,可以在不同设备上自动调整布局和显示效果。 总之,web前端文件管理器是一种非常有用的工具,可以帮助开发人员高效地管理和组织网站的文件和资源。它提供了许多方便的功能,使开发人员能够轻松地处理文件操作,并提供更好的用户体验。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值