文本文件 / 二进制文件 / 二进制bit流

计算机在存储或传输数据时都是以 bit 流的形式(二进制),文本文件和二进制文件的主要区别就是在于文本文件是有字符集的,ascii/utf8/utf16 等,读取时会将二进制流解码成对应的字符集字符。而二进制文件则简单的将数据作为二进制流处理,使用文本编辑器打开时,ascii解码,1byte 1byte 的处理并,有的落在ascii可打印字符中的就显示,没有落在其中的就是我们看到的乱码了。

例如

存储

ascii 文本数据 hello 存储的二进制流如下

存储的是每个字符的 ASCII 码

01101000 01100101 01101100 01101100 01101111

读取

按 ascii 文本文件读取

会依次读取 1byte 然后输出 ascii 码表对应的字符

为了便于比较我们这里读取 4byte 的数据

01101000 01100101 01101100 01101100

h--------e--------l--------l-------

按二进制流文件读取

可以读取 4byte 作为 uint 解析

二进制:01101000 01100101 01101100 01101100

十进制:|------------1751477356-----------|

可以读取 2byte 作为 usint 解析

二进制:01101000 01100101 01101100 01101100

十进制:|-----26725-----| |-----27756-----|

所以,文本文件和二进制文件的不同之处是解析方式不同,文本文件需要按照自身字符集,截取相应的字节长度读取,ascii 1byte, utf8 英文 1byte/中文 3byte, unicode 2byte 的方式去一段段的读取解析,二进制文件的话并没有表征性的字符集,你可以按自己的需要解析,比如第1 byte位代表的什么(unsigned short int / short int / ascii?),第2~3 byte位代表的什么,第n~k byte位代表的什么。

因为 ascii 的 char 和 int 的存储方式本质一致的(C语言里 char 类型本质就是 int),所以用多字节可能更好理解。

// uft8 存储中文字符使用 3byte 这里我们将其拆成字节码后分别获取对应的二进制

foreach (str_split("我") as $key => $chr) {

echo sprintf("%08d", decbin(ord($char))) . ' ';

}

// result

11100110 10001000 10010001

所以,如果我们使用 utf8 字符集处理 11100110 10001000 10010001时,我们得到的是 “我”。

如果我们将其作为二进制文件处理的话得到的结果是int(15108241)数值。

// 将二进制字符串转为对应的十进制

echo bindec('111001101000100010010001');

//result

int(15108241)

hex2bin / bin2hex

其实这俩货让我迷惑了很久,很长一段时间我都不明白他俩到底有什么用,输出结果不难理解,还被同事的代码带过节奏,因为我看到他经常在发送数据前通过 bin2hex 转化一下再发送,我惯性的认为难不成可以压缩数据量?

而这一次,我很刻意的将 hex2bin写在了 bin2hex的前面。

hex2bin 打包

hex2bin(hexString)的作用是将字符串作为十六进制的模式进行处理,如何处理,"68656c6c6f"会被处理成"68" "65" "6c" "6c" "6f",然后转换成对应的二进制数据(注意:是二进制数据,不是二进制数据对应的二进制字符串,decbin 方法提供这一功能,将数据转换成二进制对应的字符串),"68"(注意是字符串 2bytes)转为二进制数值是 01101000(注意是数值 1byte),输出至终端其实就是h(1bytes)的,依次处理后,我们成功的将10bytes的字符串"68656c6c6f"转换成了5bytes的字符串"hello",只不过"hello"并不是我们真正需要的数据,虽然你对它很亲切。

不要被"hello"迷惑了,最初我看到它时很难把它和bin联系到一起。"hello"是你的编辑器对hex2bin后的二进制流进行处理时,把二进制流当做文本处理(它们是文本编辑器,自然会把数据作为文本处理),恰好能对应上可打印字符的ascii码,就显示了"hello",所以说文本和二进制文件底层都是bit流,看怎么处理了。

bin2hex 解包

bin2hex(binString)则是将待处理的数据的二进制bit串进行16进制转换,并返回相应的16进制形式的字符串,这里的bin是说会将其作为二进制流,转换成对应的十六进制流,然后再以对应的字符串方式返回。比如"h"的二进制bit串是01101000,对应的十六进制是 0x68,相应的字符串形式是"68",依次继续解包处理 "e" "l" "l" "o" 后得到的字符串就是"68656c6c6f"。

所以我们如果想传输字符集在'0-9a-f'内的数据,可以使用 hex2bin打包数据至二进制流节省空间,然后传输完成后再通过bin2hex解包获得源数据。

hex2bin(hexString)/bin2hex(binString) 对应 pack("H*", hexString)/unpack("H*", binString)

pack/unpack

只要提供了socket编程的语言,肯定也同时提供了 pack/unpack,pack/unpack的主要作用是方便我们将数据打包至二进制流,然后以二进制流的方式解包。

H 十六进制

将十六进制的字符串打包至二进制流字符串,这里有个很微妙的理解,比如字符串"68" 2bytes,如果作为十六进制则其对应的二进制是00110110,对应的ascii文本字符是"h" 1byte,传输后我们对h进行解包转为十六进制得到"68",这种打包-传输-解包的方式节省了一半的传输量。

比如我们有一串字符串数据"68656c6c6f",如果直接传输的话需要strlen("68656c6c6f") = 10 byte,你会发现这串数据完全符合十六进制模式,如果进行如下处理我们可以节省了一半的传输数据量。

// 符合十六进制的字符串 0-9a-f

$data = "68656c6c6f";

echo "src data len:" . strlen($data) . PHP_EOL;

// 发送端 将 16进制 的字符串打包至 2进制

$package = pack("H*", $data);

//如果你输出 $package 你会发现它是 "hello"

echo "packed data len:" . strlen($package) . PHP_EOL;

// 传输的数据量为 strlen($package) 个字节

// 接收端解包

$data = unpack("H*", $package);

var_dump($data);

以上功能可以用 hex2bin/bin2hex实现

// 符合十六进制的字符串 0-9a-f

$data = "68656c6c6f";

foreach (str_split($data) as $char) {

echo sprintf("%08d", decbin(ord($char))) . ' ';

}

echo "data len: " . strlen($data) * 8 . ' bits' . PHP_EOL;

$package = hex2bin($data);

foreach (str_split($data) as $char) {

echo sprintf("%08d", decbin(ord($char))) . ' ';

}

echo "package len: " . strlen($package) * 8 . ' bits' . PHP_EOL;

$data = bin2hex($package);

var_dump($data);

其实你会发现作为打包传输的数据是hello,这里可能有些反客为主的惯性思维,因为大部分时间对我们有意义的数据是hello而不是 68656c6c6f,但在这里68656c6c6f才是我们需要的数据,打包后得到的hello反而是压缩传输的中间数据。

n 无符号16位整形大端序 / N 无符号32位整形大端序

n是无符号短整型,固定2bytes,可以将0 ~ 65536内的数值用固定2bytes表示,比如 "65536"用字符串表示需要5bytes,以 n 模式打包至二进制后只需要 2bytes,节省了传输空间。

N是无符号整形,固定4bytes,可以将0~4294967296内的数值用固定4bytes表示。

当然,可能你的数值字符串是"0~99"的时候节省空间的优点并不明显,但另一个优点一直存在,那就是长度固定,在一些协议传输时dataLen . data的包结构是很需要dataLen是固定字节的数据。

比如

// package struct

00000000 00000001 00110110

|---dataLen 1---| |data h|

我们取数据包 package 的前2bytes解包后得到的数值就是数据包消息体的长度,如上所示长度为 1,后面的data即为1bytes 'h'。

在tcp流式数据时是很必须的,因为如果没有包长度声明,发送端连续发送多条消息,可能会导致粘包,接收端没办法正确的拆分消息:msg1msg2msg3 可能会被拆分成 "msg" "1msg2ms" "g3"。

而声明了包长度后,我们可以先读取固定长度的字节获取到消息体长度,再读取相应长度的消息体内容。

$foo = "hello world";

$bar = "i am sqrt_cat";

$package = "";

// 使用 n 打包 固定2bytes

$fooLenn = pack("n", strlen($foo));

$package = $fooLenn . $foo;

$barLenn = pack("n", strlen($bar));

$package .= $barLenn . $bar;

// 传输 $package "fooLen . foo . barLen . bar"

// 取前 2bytes 按 n 解包

$fooLen = unpack("n", substr($package, 0, 2))[1];

// 使用包消息体长度定义读取消息体

// 从第 3byte 开始读 前 2bytes表示长度

$foo = substr($package, 2, $fooLen);

echo $foo . PHP_EOL;

// 0 ~ (2 + fooLen) - 1 字节序为 fooLen . foo

// (2 + fooLen) ~ (2 + fooLen) + 2 - 1 为 barLen

$barLen = unpack("n", substr($package, (2 + $fooLen), 2))[1];

$bar = substr($package, (2 + $fooLen) + 2, $barLen);

echo $bar . PHP_EOL;

这样就可以灵活的解析流数据,在一些情况下还节省了空间。

java hex2bin_hex2bin / bin2hex / pack / unpack 的理解及应用相关推荐

  1. [转]PHP: 深入pack/unpack

    From : http://my.oschina.net/goal/blog/195749 http://www.w3school.com.cn/php/func_misc_pack.asp PHP作 ...

  2. PHP: 深入pack/unpack

    为什么80%的码农都做不了架构师?>>>    PHP作为一门为web而生的服务器端开发语言,被越来越多的公司所采用.其中不乏大公司,如腾迅.盛大.淘米.新浪等.在对性能要求比较高的 ...

  3. pack unpack 用法 转载

    原本转自于 https://segmentfault.com/a/1190000008305573 PHP中有两个函数pack和unpack,很多PHPer在实际项目中从来没有使用过,甚至也不知道这两 ...

  4. java局部变量全局变量,实例变量的理解

    java局部变量全局变量,实例变量的理解 局部变量 可以理解为写在方法中的变量. public class Variable {//类变量static String name = "小明&q ...

  5. 阿里JAVA开发手册零度的思考理解(二)

    转载请注明原创出处,谢谢! 说在前面 人生的大道上默默地走,就必须要有一盏灯亮着为你引导方向!而这盏灯抑或只是一句话,一句鼓励,一个赞美,一次承认,一次认可,一次相识一次交流-- 上篇文章:阿里JAV ...

  6. python3 struct模块 处理二进制 pack unpack用法

    python有时需要处理二进制数据,例如 存取文件,socket操作时.这时候,可以使用python的struct模块来完成.可以用struct来处理c语言中的结构体. struct模块中最重要的三个 ...

  7. java static关键字_好程序员Java教程分享static关键字的理解

    好程序员Java教程分享static关键字的理解,static关键字含义可以理解为静态的. 1. 当其修饰属性时,该属性为整个类公有,所有的对象操作的都是同一个静态属性.所以调用时应该使用类名去调用, ...

  8. Java受查异常和运行时异常的理解

    Java受查异常和运行时异常的理解 概念与理解 怎么处理 概念与理解 Java提供三种可抛出结构(throwable):受查异常(checked exception),运行时异常(runtime ex ...

  9. Java生鲜电商平台-深入理解微服务SpringCloud各个组件的关联与架构

    Java生鲜电商平台-深入理解微服务SpringCloud各个组件的关联与架构 概述 毫无疑问,Spring Cloud是目前微服务架构领域的翘楚,无数的书籍博客都在讲解这个技术.不过大多数讲解还停留 ...

  10. Java语言程序设计 上机实验2 掌握Java的基本语言成分和流程控制语句。 掌握Java中数组的使用,理解引用数据类型。 掌握String类的使用。...

      Java语言程序设计 上机实验2 实验目的: 掌握Java的基本语言成分和流程控制语句. 掌握Java中数组的使用,理解引用数据类型. 掌握String类的使用. 实验内容: 注:标(*)为选做内 ...

最新文章

  1. 是时候开始使用JavaScript严格模式了怎样启用javascri
  2. greenDAO缓存遇到的大坑的解决方法
  3. 数据库事务原理及并发、死锁
  4. Curl操作es实践
  5. php编译优化,浅析使用Turck-mmcache编译来加速、优化PHP代码
  6. payara 创建 集群_在Payara Server和GlassFish中配置密码
  7. 华为户外模式怎么设置_华为FreeLace Pro降噪器效果怎么样?降噪开启和设置教程!...
  8. Springboot实现的医院分针挂号住院管理系统
  9. 20190911:(leetcode习题)计数质数
  10. 实验4 数据库的连接查询
  11. 局域网电脑资产搜集管理
  12. 《信号检测与估值理论》Matlab仿真,包括: 高斯-牛顿迭代法对正弦信号参数进行估计
  13. 线性代数学习笔记——第三十五讲——平面与平面的位置关系
  14. App后台开发(学习笔记)
  15. 软件工程课程设计-ch小说网站
  16. Steam流式传输后插耳机没有声音
  17. 目标客户画像_做营销时,如何做好目标用户群体画像?
  18. nltk.stem.WordNetLemmatizer()时报错BadZipFile(“File is not a zip file“)的解决方法
  19. Yolov5检测并生成文本及标签文件
  20. LabVIEW编程开发Agilent 34401A(Keysight 34401A)例程与相关资料

热门文章

  1. pdf reference官方指南之-图片
  2. html怎么把新闻列表放在右边,div+css实现简洁、清晰的新闻列表样式(浮动使日期靠右)...
  3. 关于Qt的dateTime和时间戳转化数据不对的问题
  4. CSDN:数学公式编辑器
  5. 【安装记录】Centos7.6下载安装配置教程(十分详细)
  6. 我的工程师进阶之路 - 2022更新
  7. 【CVPR 2021联邦学习论文解读】Model-Contrastive Federated Learning (MOON) 联邦学习撞上对比学习
  8. ATTCK实战系列一(内网渗透入门)
  9. 智能玩具小风扇制作教程
  10. c语言彩票号码生成器