Skip to main content

文件类型之文本文件和二进制文件

· 12 min read

概要

本文讲述以下内容:

  • 文本文件和二进制文件,二者的本质区别(存储和传输,以及表示)
  • 为什么要进行base64编码,以及编码原理
  • 介绍几种常见的/经典的编码和字符集
  • JS中的Blob、Stream、Buffer FormData等
  • 前端项目请求实例封装中的文件/图片上传
  • FileReader接口(以及一系列的WebAPI)

文件类型

Q: 首先什么是文件?

A: 在计算机中文件就是存储在某种存储设备中的一段 数据,其作用就是在需要的时候可以取来使用。

在计算机中我们通常将文件分为两种,文本文件二进制文件

所谓文本文件指的就是我们可以直接通过文本编辑器,比如记事本、各类编程开发工具进行查看其内容的文件;文本文件通常都是 经过一定的字符编码的,比如最常见的ASCII编码,但其本质依旧是二进制文件, 因为在计算机看来所有的文件都是二进制的, 计算机也只认识二进制(0101...)。那我们今天说的二进制文件就是相对与文本文件而言的,二进制文件无法通过文本编辑器查看其内容, 而必须借助专门的软件程序进行打开查看,比如图片文件需要用图片查看器、音乐文件需要用到音频播放器、视频文件需要用到视频播放器等等..

info

文本文件是基于字符编码的文件,常见的有ASCII、Unicode等;二进制文件是基于值编码的文件,可以根据具体的应用,指定某个值是什么意思(这一过程,可以视作自定义编码,如果你定义了自己的一套编码规则,并能将数据正确的以某种形式读取出来应用的话,那么你其实是发明/创造了一种新的应用程序。)

文件的存储:在计算机的硬盘中无论是文本文件还是二进制文件都是以字节这种二进制形式存储的,当文件被读取的时候,文本文件从字节数据按照字符编码规则转换成字符数据,二进制文件比如图片会按照图像的压缩算法、色彩空间等进行图像的解码最终展示在屏幕上。

caution

网上似乎有一个迷思说二进制文件的存取效率比文本文件高?但是却又没人能解释清楚为什么高,哪个阶段高了。在我看来二进制数据就是数据结构更加紧凑所以可能更加的节省磁盘空间,单从存储和读取的过程来看,二者并没有差别, 第一存储:文本文件需要进行文本字符到二进制编码的过程存到磁盘,而一张图片你在PS中编辑完后保存同样也有图像信息转换成二进制的转换过程。 第二读取:从磁盘读取一个文本文件的二进制数据,需要进行ASCII编码转换成文本字符展示,而打开一张图片同样有字节数据到图像信息的转换过程。

Base64编码

Base64编码是从二进制值到某些特定字符的编码,这些特定字符一共64个,所以称为Base64.

tip

Q: 为什么不直接传输二进制呢,比如图片(其实也可以)既然实际传输时它们都是二进制字节流。而且使用Base64编码的过的字符串最终也是 二进制在网络上传输,那么用4/3倍带宽传输数据的Base64究竟有什么意义呢?

A: 真正的原因是为了兼容。 在网络的整个传输过程中会途径非常多的中间设备、路由器、网关、集线器、转发器...某些二进制的值,在一些硬件上比如在不同品牌的路由、老电脑上 表示的意义是不一样的,做的处理也不一样甚至在一些老的软件网络协议上也有类似的问题,但是万幸的是,Base64使用的这64个字符经过ASCII/UTF-8编码之后在绝大多数机器上,软件的行为是一致的。

ASCII编码

ASCII编码总共128个,其中不可打印字符33个 (0 ~ 31 + 第 127),可打印字符95个 (32 ~ 126)。

ASCII 编码一览表(淡黄色背景为控制字符,白色背景为可显示字符)
二进制十进制十六进制字符/缩写解释
00000000000NUL (NULL)空字符
00000001101SOH (Start Of Headling)标题开始
00000010202STX (Start Of Text)正文开始
00000011303ETX (End Of Text)正文结束
00000100404EOT (End Of Transmission)传输结束
00000101505ENQ (Enquiry)请求
00000110606ACK (Acknowledge)回应/响应/收到通知
00000111707BEL (Bell)响铃
00001000808BS (Backspace)退格
00001001909HT (Horizontal Tab)水平制表符
00001010100ALF/NL(Line Feed/New Line)换行键
00001011110BVT (Vertical Tab)垂直制表符
00001100120CFF/NP (Form Feed/New Page)换页键
00001101130DCR (Carriage Return)回车键
00001110140ESO (Shift Out)不用切换
00001111150FSI (Shift In)启用切换
000100001610DLE (Data Link Escape)数据链路转义
000100011711DC1/XON
(Device Control 1/Transmission On)
设备控制1/传输开始
000100101812DC2 (Device Control 2)设备控制2
000100111913DC3/XOFF
(Device Control 3/Transmission Off)
设备控制3/传输中断
000101002014DC4 (Device Control 4)设备控制4
000101012115NAK (Negative Acknowledge)无响应/非正常响应/拒绝接收
000101102216SYN (Synchronous Idle)同步空闲
000101112317ETB (End of Transmission Block)传输块结束/块传输终止
000110002418CAN (Cancel)取消
000110012519EM (End of Medium)已到介质末端/介质存储已满/介质中断
00011010261ASUB (Substitute)替补/替换
00011011271BESC (Escape)逃离/取消
00011100281CFS (File Separator)文件分割符
00011101291DGS (Group Separator)组分隔符/分组符
00011110301ERS (Record Separator)记录分离符
00011111311FUS (Unit Separator)单元分隔符
001000003220(Space)空格
001000013321! 
001000103422" 
001000113523# 
001001003624$ 
001001013725% 
001001103826& 
001001113927' 
001010004028( 
001010014129) 
00101010422A* 
00101011432B+ 
00101100442C, 
00101101452D- 
00101110462E. 
00101111472F/ 
0011000048300 
0011000149311 
0011001050322 
0011001151333 
0011010052344 
0011010153355 
0011011054366 
0011011155377 
0011100056388 
0011100157399 
00111010583A: 
00111011593B; 
00111100603C< 
00111101613D= 
00111110623E> 
00111111633F? 
010000006440@ 
010000016541A 
010000106642B 
010000116743C 
010001006844D 
010001016945E 
010001107046F 
010001117147G 
010010007248H 
010010017349I 
01001010744AJ 
01001011754BK 
01001100764CL 
01001101774DM 
01001110784EN 
01001111794FO 
010100008050P 
010100018151Q 
010100108252R 
010100118353S 
010101008454T 
010101018555U 
010101108656V 
010101118757W 
010110008858X 
010110018959Y 
01011010905AZ 
01011011915B[ 
01011100925C\ 
01011101935D] 
01011110945E^ 
01011111955F_ 
011000009660` 
011000019761a 
011000109862b 
011000119963c 
0110010010064d 
0110010110165e 
0110011010266f 
0110011110367g 
0110100010468h 
0110100110569i 
011010101066Aj 
011010111076Bk 
011011001086Cl 
011011011096Dm 
011011101106En 
011011111116Fo 
0111000011270p 
0111000111371q 
0111001011472r 
0111001111573s 
0111010011674t 
0111010111775u 
0111011011876v 
0111011111977w 
0111100012078x 
0111100112179y 
011110101227Az 
011110111237B 
011111001247C| 
011111011257D} 
011111101267E~ 
011111111277FDEL (Delete)删除

前端项目中封装请求实例的content-type

先说结论

1、Post请求简单表单数据:Content-Type: application/x-www-form-urlencoded

info

通常被用于HTML表单提交,数据会被编码成键值对的形式

2、Post请求,JSON数据:Content-Type: application/json

info

当通过 POST 请求发送 JSON 格式的数据时,应该使用这个 Content-Type。这在现代 Web 开发中很常见,特别是与 RESTful API 一起使用

3、POST请求,文件上传:Content-Type: application/form-data

info

用于通过 POST 请求上传文件。常用于表单中包含文件上传的场景

4、POST请求,纯文本数据:Content-Type: text/plain

info

用于发送纯文本数据。

5、Get请求,一般不包含请求体,但是如果包含了一般使用 Content-Type: application/x-www-form-urlencoded 或者 Content-Type: text/plain

6、XML 数据:Content-Type: application/xml, 当需要发送或接收 XML 数据时使用.

tip

Content-Type 既可以出现在请求头中,也可以出现在响应头中。在 HTTP 协议中,Content-Type 是用来指示实体正文的媒体类型的标头字段。

因此,Content-Type 是一个常见的请求头和响应头字段,用于确保发送和接收的数据以正确的格式进行解析。在请求头中,它告诉服务器请求正文的格式,而在响应头中,它告诉客户端返回数据的格式。

关于 responseType

responseTypeFetch API 中请求配置对象的一个属性,因此他是请求头的一部分,用于指定服务器响应 的数据类型。axios 是一个基于Promise的http客户端库,它在使用上很类似于Fetch API,并且也提供了类似的 配置项其中包括responseType.

可以通过配置responseType来告诉浏览器希望以什么样的数据类型来处理服务器响应。以下是一些常见的responseType

1、responseType: 'text' 将响应解析为文本字符串

2、responseType: 'json' 将响应解析为JSON对象

3、responseType: 'blob' 将响应解析为二进制数据(Blob对象)

4、responseType: 'arraybuffer' 将响应解析为二进制对象(ArrayBuffer对象)

5、responseType: 'document' 将响应解析为XML文档(可以是XML、HTML等)

6、responseType: 'stream' 用于将响应数据以Node.js 可读流的形式返回。这种形式对于处理大型响应数据或实时数据流非常有用!

FileReader

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

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

info

File对象可以看作一种特殊的Blob对象. Blob是File的父类。

方法

1、FileReader.readAsArrayBuffer(): 开始读取指定的 Blob中的内容,一旦完成,result 属性中保存的将是被读取文件的 ArrayBuffer 数据对象。

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

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

tip

当我们需要读取一个文件的时候,如果是文本文件我们就可以通过 let fr = new FileReader(); fr.readAsText('文件') 方法来读取文件内容; 而当文件是一个二进制文件的时候,我们就可以通过fr.readAsArrayBuffer('文件')来读取文件内容。

// 读取文本文件:

// 创建 FileReader 对象
const reader = new FileReader();

// 为 FileReader 设置 onload 事件处理程序
reader.onload = function(event) {
// event.target.result 包含文件的文本内容
console.log(event.target.result);
};

// 读取文本文件
const fileInput = document.getElementById('fileInput'); // 假设有一个 input 元素用于选择文件
const selectedFile = fileInput.files[0];
reader.readAsText(selectedFile);

// 读取图像文件并显示:

const reader = new FileReader();

reader.onload = function(event) {
// event.target.result 包含图像文件的 data URL
const imgElement = document.getElementById('imageElement'); // 假设有一个 img 元素用于显示图像
imgElement.src = event.target.result;
};

const fileInput = document.getElementById('fileInput'); // 假设有一个 input 元素用于选择文件
const selectedFile = fileInput.files[0];
reader.readAsDataURL(selectedFile);

// 读取二进制文件(例如,ArrayBuffer):

const reader = new FileReader();

reader.onload = function(event) {
// event.target.result 包含二进制文件的 ArrayBuffer
const arrayBuffer = event.target.result;
// 处理 ArrayBuffer
};

const fileInput = document.getElementById('fileInput'); // 假设有一个 input 元素用于选择文件
const selectedFile = fileInput.files[0];
reader.readAsArrayBuffer(selectedFile);
caution

需要注意的是,由于文件读取是异步的,因此 FileReader 使用事件处理程序(例如 onload)来捕获读取完成后的结果。