java 二进制与或_Java格式工厂(一)——什么是二进制文件?

本文介绍了Java中二进制文件的概念,包括文本文件与二进制文件的区别,如何使用Hexdump工具查看二进制文件,以及big-endian和little-endian的字节存储顺序。此外,还探讨了Java默认使用big-endian以及在处理字节序问题时的注意事项。
摘要由CSDN通过智能技术生成

前言

最近在用Java做一个文件格式转化的工具(github地址:https://github.com/lhing17/waterConverter.git),希望通过简单的调用实现一些常用格式间的互相转换,实质上是一些处理不同文件格式的工具包的整合。借此机会,也对Java怎么处理不同格式的文件有了更深入的了解,希望写一系列的文章作为记录。作为开篇,先来聊一聊什么是二进制文件,以及二进制文件到底是怎么存储信息的。

文本文件 vs 二进制文件

我们常说,文件分为文本文件和二进制文件,这其实是一种很糙的分类方式。文件是文本文件还是二进制文件,这是逻辑上的概念,而不是物理上的概念。在物理上,文件都是基于二进制来存储的,文件存储的基本单位是字节,每个字节由8个二进制位组成。如果整个文件能够被某种软件全部解码为字符串,我们就认为这个文件是文本文件。也就是说,文本文件是一种特殊的二进制文件。

同样道理,某种二进制文件如果可以按照位图的方式去解码,它就可以显示为一张图片;如果可以按照 MPEG-3的规则解码,它就可以播放为音频。一些常见的文件格式,都是使用其相应的规范进行编码的。因此,我们可以根据规范编写相应解码的软件,用于读取这些格式的文件。也有一些二进制文件的编码格式是程序开发者自定义的,这样的文件对于普通的用户来说就几乎是保密的。

规范的二进制文件通常都是由多个多字节的序列组成的,每个多字节的序列承载一部分信息。我们以Java的Class文件为例,Class文件是以无符号数和表两种结构来存储信息。

无符号数属于基本数据类型,以u1、u2、u4、u8来分别代表1个字节、2个字节、4个字节和8个字节的无符号数,无符号数可以用来描述数字、索引引用、数量值或者按照UTF-8编码构成字符串值。 表是由多个无符号数或者其他表作为数据项构成的复合数据类型,为了便于区分,所有表的命名都习惯性地以“_info”结尾。表用于描述有层次关系的复合数据,整个Class文件本质上也可以视作是一张表,这张表由下表所示的数据项按严格顺序排列构成。

表1 Class文件格式

类型 | 名称 | 数量 |:-------:|:-------:|:-------:| |u4|magic|1| |u2|minor_version|1| |u2|major_version|1| |u2|constant_pool_count|1| |cp_info|constant_pool|constant_pool_count-1| |u2|access_flags|1| |u2|this_class|1| |u2|super_class|1| |u2|interfaces_count|1| |u2|interfaces|interfaces_count| |u2|fields_count|1| |field_info|fields|fields_count| |u2|methods_count|1| |method_info|methods|methods_count| |u2|attributes_count|1| |attribute_info|attributes|attributes_count|

使用Hexdump类工具查看二进制文件

有的时候,为了开发方便,我们需要去查看二进制文件的结构。前面提到,二进制文件的基本单位是字节,一个字节是由8个二进制位(0或1)组成的。二进制书写和阅读起来都很不方便,为了读写方便,我们通常把二进制转化为16进制。16是2的4次方,因此一个16进制数可以代表4个2进制位。这样,我们就可以用两个16进制数来代表一个字节。有一些工具可以用来查看文件的16进制表示,如Hexdump。Hexdump最初是linux系统上的命令,现在VSCode等工具都提供了hexdump的插件。

图1 VSCode hexdump插件查看文件效果图

2ce34e23ed73e49f9c23230e3b53299d.png

如上图,左侧是二进制文件的16进制表示,右侧是尝试解码为字符的表示。

little-endian vs big-endian

当我们使用多个字节的序列来承载信息时,就出现了字节存储顺序的问题。我们可以把高位字节放在前面,也可以把低位字节放在前面,这就是我们平时说的little-endian和big-endian。

1)Little-endian:将低序字节存储在起始地址(低位编址) 2)Big-endian:将高序字节存储在起始地址(高位编址)

举个例子: 我们有一个整型数据1,它在内存中占据了四个字节的空间,它的16进制表示为:

0x00 00 00 01

在内存中怎么存储呢? 如果你的CPU是intel x86架构的(基本上就是通常我们说的奔腾cpu),那么就是0x01 0x00 0x00 0x00 , 这也就是所谓的little-endian, 低字节存放在内存的低位。如果你的CPU是老式AMD系列的(很老很老的那种,因为最新的AMD系列已经是x86架构了), 它的字节序就是big-endian, 其内存存储就是 0x00 0x00 0x00 0x01在内存中从高字节开始存放。

Java是big-endian还是little-endian?

Java默认采用big-endian方式,如各种读写流中的readInt()方法都是从高位到低位读取四个字节转化为整数。如果文件的读写都是通过Java来实现的,我们通常不需要去关注字节序的问题。但是如果与那些不是使用Java编写的程序交换数据文件时,就需要考虑字节序的问题了。

参考文献

周志明《深入理解Java虚拟机》

Big Endian 和 Little Endian 详解。原文链接:https://blog.csdn.net/waitingbb123/java/article/details/80504093

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值