当前位置: 首页 > article >正文

二进制文件与文本文件的区别【字符集Charset】

计算机上存储的文件在比特位上都是以二进制数字0或1表示,因此在物理层面上,文本文件和二进制文件没有本质差异,都是由数字0或1组成的比特位集合。

文本文件和二进制文件,两者的差异体现在编码逻辑,需要根据文件头中标记来区分。

文本文件是基于字符编码的文件,通常文件头有“字节序标记”BOM。什么是BOM?
不同的字符编码方案有固定的BOM标记。文本读写应用程序通常是根据BOM来确认文本的编码格式,然后才能处理文件中的信息。
在这里插入图片描述

二进制文件由二进制数字0和1组成,不同应用有不同的编码方案,通常也有文件头信息。。例如,音频、视频和图像文件都属于二进制文件,它们也各有编码方案,需要专用程序来处理。有的二进制文件也有“字节序标记”BOM,其作用主要为了确认编码是大端还是小端,用于确认编码方案中每组字节的编码排列顺序。

比如 bmp文件,它的文件头信息,前2个字节表示文件格式为BMP格式,接着的 8个字节表示文件的长度,再接着的4个字节表示 bmp文件头的长度。然后再根据BMP文件的编码方案可以解释出绘制图像。

win10系统文本文件的编码方案
win10系统默认的字符集(Charset)是GBK。
我们可用下面的Java程序来打印win10系统默认的字符集,以及支持的字符集:

/***
 * @author QiuGen
 * @description  系统默认字符集(Charset)打印例程CharsetPrn.java
 * @date 2024/9/16
 * ***/
import java.nio.charset.Charset;	//程序CharsetPrn.java开始
import java.util.SortedMap;
public class CharsetPrn {
	public static void main(String[] args) {
		Charset charset = Charset.defaultCharset(); //获取系统环境的默认字符集名
		System.out.println("当前系统环境的默认字符集名称");
		System.out.println(charset);
		System.out.println("当前系统环境的可用字符集名称");
		SortedMap<String,Charset> map = Charset.availableCharsets();
		map.forEach((k,v)->System.out.println(k));
	}
}

在win10系统下的字符编码方案有以下几种,ASCII,ANSI、UTF-8、带有BOM的UTF-8 、UTF-16LE、UTF-16BE。
win10系统默认的字符集(Charset)编码方案是GBK编码。

这几种编码的特点:

(1) ANSI和ASCII编码: ASCII编码是ANSI编码的子集。ANSI编码是兼容ASCII编码的,如果字节的最高位是0(0-7F),二进制形如0XXX XXXX,表达的是ASCII字符。如果字节的最高位是1(80-FE),则是ANSI(GBK)编码,注意,这时候是两个字节表达一个汉字,也就是说两个字节的最高位都是1的字节代表一个汉字,二进制形如1XXX XXXX, 1XXX XXXX 。

在ANSI编码下,如果文本字符都是西文字符,则也可以认为是ASCII编码,当有连续高为是1的字节串出现的时候,这是可以判定为ANSI或GBK编码。GBK编码一定是两个高位均为1的字节表达一个汉字。ANSI每个字节的高位可以是1或0,若字节高位是0,则一个字节表达一个ASCII字符。

(2) UTF-8编码:utf-8是一种多字节编码的字符集,表示一个Unicode字符时,它可以是1个至多个字节。即在文本全部是ASCII字符时utf-8是和ASCII一致的(utf-8向下兼容ASCII)。最多6个字节表达一个字符,utf-8字节编码如下所示:
1字节:0xxxxxxx
2字节:110xxxxx 10xxxxxx
3字节:1110xxxx 10xxxxxx 10xxxxxx ,一般汉字用这个3字节表达
4字节:11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
5字节:111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
注意,在UTF-8编码中,多种长度是混合存在的,一个字符串可能有1,2,…,6个字节来表示的字符同时存在 。因此UTF-8编码太复杂,效率较低。

(3)有“字节序标记”BOM的UTF-8,其文本文件的头部带有“字节序标记”BOM:0xEF, 0xBB,0xBF,通过判断这个标志,可以判断出这个文本文件是UTF-8编码。

(4)UTF-16LE,字节序是little endian ,是双字节等长编码。文本文件头部带有“字节序标记”BOM:0xFF 0xFE,通过判断这个标志,可以判断出这个文本文件是UTF-16LE编码。

(5) UTF-16BE, 字节序是big endian,是双字节等长编码。文本文件头部带有“字节序标记”BOM:0xFE 0xFF,通过判断这个标志,可以判断出这个文本文件是UTF-16BE编码。

下面是一个根据“字节序标记”BOM测试文本文件编码方案的例程:

/***
 * @author QiuGen
 * @description  根据BOM测试文本文件编码方案例程
 * FileCharsetDetector.java
 * @date 2024/9/16
 * ***/
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
public class FileCharsetDetector {

	public static void main(String[] args) {
        String filePath = "D:/temp/测试文档2.txt";
        
        try (FileInputStream in = new FileInputStream(filePath)) {
            Charset charset = null;
            int bom[] = new int[3];
            bom[0] = in.read(); //读第1个字节
            bom[1] = in.read(); //读第2个字节
            bom[2] = in.read(); //读第3个字节
            //打印BOM
            System.out.println("BOM:"+Integer.toHexString(bom[0])+Integer.toHexString(bom[1])+Integer.toHexString(bom[2]));
            if (bom[0] == 0xFE && bom[1] == 0xFF) {
                charset = StandardCharsets.UTF_16BE;
            } else if (bom[0] == 0xFF && bom[1] == 0xFE) {
                charset = Charset.forName("UTF-16LE");
            } else if (bom[0] == 0xEF && bom[1] == 0xBB && bom[2] == 0xBF) {
                charset = StandardCharsets.UTF_8;
            } else {
                charset = Charset.forName("GBK");
            }
            
            System.out.println("文件字符编码: " + charset.name());
        } catch (IOException e) {
            e.printStackTrace();
        }
	}

}

在win10环境,使用文本编辑器应用程序“记事本”,分别编写四个文件分别保存为UTF-16LE、 UTF-16BE、UTF-8和ANSI编码格式的文本。进行测试,UTF-16LE和 UTF-16BE能准确打印出BOM,下图是UTF-16LE的测试结果。

在这里插入图片描述
UTF-8和ANSI编码格式的文本,测试结果一样,如下所示:
在这里插入图片描述
由此说明Win10的UTF-8文本文件文件头中没有标准的“字节序标记”BOM。


http://www.kler.cn/a/320700.html

相关文章:

  • el-table中增加校验方法(二)
  • git push时报错! [rejected] master -> master (fetch first)error: ...
  • 222. 完全二叉树的节点个数【 力扣(LeetCode) 】
  • 【小白可懂】微信小程序---课表渲染
  • 如何使用Django写个接口,然后postman中调用
  • 基于Java Web 的家乡特色菜推荐系统
  • 安卓13设置动态修改设置显示版本号 版本号增加信息显示 android13增加序列号
  • 23个Python在自然语言处理中的应用实例
  • GEE 高阶应用:基于 BFAST 类型模型的近实时干扰检测
  • CemtOS7安装Nginx
  • 排序题目:对角线遍历 II
  • 【Go】-viper库的使用
  • 科研绘图系列:R语言组合多个图形
  • 寿司检测系统源码分享
  • 数据科学基石:解析属性类型体系——从标称到比率,全面洞察数据分类机制
  • 粒子向上持续瀑布动画效果(直接粘贴到记事本改html即可)
  • 1. go 环境
  • CentOS 系统上解压并安装 Python 3.12.6
  • Helm介绍安装使用
  • 饿了么基于Flink+Paimon+StarRocks的实时湖仓探索
  • 企业如何使用数据分析管理系统
  • 从准备面试八股文,感悟到技术的本质
  • Flutter局域网广播(UDP通信)与TCP通信
  • ant design vue做表单验证及form表单外验证、父子嵌套多个表单校验
  • MySQL篇(leetcode刷题100(查询))(二)(持续更新迭代)
  • 美食雷达:Spring Boot校园美食探索工具