字节流与位流的相互转换实现

简介: 引言:在项目开发中,我们会遇到字节流与比特流相互转换、逐字节、逐位操作的场景。没有现成的库供我们调用,需要我们自己实现之。

一、字节流、位流介绍


      【维基百科--字节流】:在计算机科学里面,字节流(byte stream)是一种位流,不过里面的比特被打包成一个个我们叫做字节(Bytes)的单位。


      【字节流范例】:在网络传输协议里面比较有名,且会提供字节流给客户端的范例是TCP/IP通讯协定里面的传输控制协议(TCP),这种协议提供了双向的字节流。


      【维基百科--位元流】:一个位元流(bitstream或bit stream)是一个位元的序列。一个字节流则是一个字节的序列,一般来说一个字节是8个位元。也可以被视为是一种特殊的位元流。


       【位元流范例】:位元流在远程通信和计算这些领域里面被广泛的使用:举例来说,同步光网络通信科技会传输同步位元流。


        在项目的开发中,我们经常会遇到对于给定的字符串“0123456789abcdef”(字节流,16个字节),我们需要其转化为对应的二进制位流(其中0对应的ASCII码元为0x30,对应二进制为00110000,一个字节用8个二进制模拟输出,合计16*8=128个二进制数据)。


        没有现成的库函数供我们调用,所以考虑字节流的特点,加上位元算的操作,以下是其相互转换的完整的实现及测试用例。


二、字节流转为位流的核心操作——如何获取到每一位


      方法:通过右移操作,然后与1(0000 0001)求与的方式。


      如下表所示,依次实现0x30右移动(1,2,3,4…)位,然后与0000 0001进行与操作;显然,只有当移动到的末位为1时两者与操作才为1(右移动4位),其他都为0。如:


初始


右移0位 >>0


0x30


00110000


右移1位


右移1位 >>1


0x18


00011000


右移2位


右移2位 >>2


0x0c


00001100


右移3位


右移3位 >>3


0x06


00000110


右移4位


右移4位 >>4


0x03


00000011



三、位流转为字节流的核心:如何将8位合为一个字节


比特流


字节流


0011 0000


0*128+0*64+1*32+1*16+0=48(10进制)=0x30(16进制)


         方法一:通过传统每位与基数相乘累计求和的方式实现。


         方法二:每8位一个单元,”或”的方式模拟求和(与字节流转化为位流方法相反),详见代码。


四、位流与字节流相互转化的实现


#include <string.h>

#include <stdio.h>

#include <stdlib.h>

#include <assert.h>

#include <iostream>

using namespace std;

#define  UCHAR  unsigned char

const int MULTIPLE = 8;       //字节流长度是位流的8倍

const int FIX_VAL = 0X01;     //求&专用特定值

const int g_BinArr[MULTIPLE] = {128,64,32,16,8,4,2,1}; //2的次幂

/*

**@brief 字节流转为位流

**@param [in]puchByte,字节流;[in]iByteLen,字节流长度;

  [in&out]puchBit,位流; [in&out]iBitLen,位流长度

**@return 空

*/

void byte_to_bit(const UCHAR *puchByte, const int& iByteLen, UCHAR *puchBit, int *pBitLen)

{

assert(puchByte != NULL && iByteLen >0 && puchBit != NULL && pBitLen !=NULL);

int iBitLen = 0;

for (int i = 0; i < iByteLen; i++)

{

 for(int j = 0; j < MULTIPLE; j++)

 {

  //printf("%0x >> %d = %0x\n", puchByte[i], j, puchByte[i]>>j);

  puchBit[i*MULTIPLE + MULTIPLE - 1 - j] = ((puchByte[i])>>j)&FIX_VAL;

  iBitLen++;

 }//end for j

}//end for

*pBitLen = iBitLen;

}



/*

**@brief 位流转为字节流

**@param [in]puchBit,位流;[in]iBitLen,位流长度;

  [in&out]puchByte,字节流 [in&out]pByteLen,字节流长度

**@return 空

*/

void bit_to_byte(const UCHAR *puchBit, const int& iBitLen, UCHAR *puchByte, int* pByteLen)

{

assert(puchBit && iBitLen > 0 && puchByte && pByteLen);

int iByteNo = 0;  

int iBitInByte = 0;

for(int i = 0; i < iBitLen; i++)

{

 iByteNo = i/MULTIPLE;    //字节序号

 iBitInByte = i%MULTIPLE; //字节里的比特序号(0-7)

 puchByte[iByteNo] += puchBit[i]*g_BinArr[iBitInByte];  //累计求和

 

 //cout << "iByteNo =:" << iByteNo << "\t iBitInByte = " << iBitInByte \

 //<< "\t puchByte[iByteNo] = " << puchByte[iByteNo] << endl;

}//end for i

*pByteLen = iBitLen/MULTIPLE;

}



/*

**@brief 位流转为字节流[方法二]

**@param [in]puchBit,位流;[in]iBitLen,位流长度;

  [in&out]puchByte,字节流; [in&out]字节流长度

**@return 空

*/

void bit_to_byte_ext(const UCHAR *puchBit, const int& iBitLen, UCHAR *puchByte, int* iByteLen)

{

assert(puchBit && iBitLen > 0 && puchByte && iByteLen);

int iByteNo = 0;              //字节号

UCHAR uchTmp = 0;

for(int i = 0; i < iBitLen; i+=MULTIPLE)

{

 for(int j = 0; j < MULTIPLE; j++)

 {

  //通过或的方式累计求和

  uchTmp |= ((puchBit[i + j])<<(MULTIPLE - 1 - j));

 }

 //printf("uchTmp = %0x\n",uchTmp);

 puchByte[iByteNo] = uchTmp;

 

 iByteNo++;    //字节号+1

 uchTmp = 0;

}//end for i

*iByteLen = iByteNo;

}

/*

**@brief 测试位流与字节流互转

**@param  空

**@return 空

*/

void test_byte_bit()

{

const UCHAR uchByte[] = "0123456789abcdef";        //原始字节流

int iByteLen = sizeof(uchByte)/sizeof(UCHAR) - 1;  //原始字节流长度

int iBitLen = MULTIPLE*iByteLen;                   //比特流长度

UCHAR *puchBit = new UCHAR[iBitLen];

memset(puchBit, 0, iBitLen);

cout << "原始字节流为: ";

#if 0

for (int i = 0; i < iByteLen; i++)

{

 printf("%0x\t", uchByte[i]);                  

}

printf("\n");

#endif

cout << uchByte << endl;

int iBitLenX = 0;

byte_to_bit(uchByte, iByteLen, puchBit, &iBitLenX);  //字节转化为比特流

cout << "测试字节流转化过的位流为: " << endl;

for (int i = 0; i < iBitLen; i++)

{

 printf("%0x",puchBit[i]);

}

printf("\n");

cout << "位流长度为: " << iBitLenX << endl << endl;

UCHAR* puchByte = new UCHAR[1 + iByteLen];

memset(puchByte, 0, 1 + iByteLen);

int iByteLenX = 0;

#if 1

bit_to_byte(puchBit, iBitLen, puchByte, &iByteLenX);    //比特流转化字节流方法1

#endif

#if 0

bit_to_byte_ext(puchBit, iBitLen, puchByte, &iByteLenX); //比特流转化字节流方法2

#endif

cout << "测试位流转化过的字节流为: " << endl;

for (i = 0; i < iByteLen; i++)

{

 printf("%0x\t",puchByte[i]);

}

printf("\n");

cout << "位流转为成的字节流为: " << puchByte << endl;

cout << "字节流的长度为: " << iByteLen << endl;

if (puchBit != NULL)

{

 delete []puchBit;

 puchBit = NULL;

}

if (puchByte != NULL)

{

 delete []puchByte;

 puchByte = NULL;

}

}

int main()

{

test_byte_bit();

return 0;

}

image.png

五、结语:

      根据代码走读,会加深对于字节流与位流相互转换的理解。


相关文章
|
21天前
字节流和字符流
字节流和字符流
11 0
|
7月前
|
存储 Java
IO流之 字节流 & 字符流
大多数应用程序都需要实现与设备之间的数据传输,例如键盘可以输入数据,显示器可以显示程序的运行结果等。在Java中,将这种通过不同输入输出设备(键盘,内存,显示器,网络等)之间的数据传输抽象的表述为“流”,程序允许通过流的方式与输入输出设备进行数据传输。Java中的“流”都位于Java.io包中,称之为IO(输入输出)流。IO流即InputOutput的缩写。一切文件数据在存储时,都是以二进制数字的形式保存,都一个一个的字节,那么传输时一样如此。所以,字节流可以传输任意文件数据。httpshttps。...
94 0
|
8月前
|
自然语言处理
转换流,字节字符的转换
转换流,字节字符的转换
|
10月前
|
存储 移动开发 索引
字节流
字节流
47 0
|
存储 Java
IO流常用类(字节流、字符流、缓冲流)使用详解(一)
IO流常用类(字节流、字符流、缓冲流)使用详解(一)
241 0
IO流常用类(字节流、字符流、缓冲流)使用详解(一)
|
存储 Java
【JAVA】编码表,字符流,对象流,其他流(一)
【JAVA】编码表,字符流,对象流,其他流
【JAVA】编码表,字符流,对象流,其他流(一)
|
设计模式 Java API
【JAVA】编码表,字符流,对象流,其他流(二)
【JAVA】编码表,字符流,对象流,其他流
字符串与字节数组转换
字符串与字节数组转换
81 0
|
存储 Java
字节缓冲流构造方法、字节流复制视频、字符流及编码表介绍
字节缓冲流构造方法、字节流复制视频、字符流及编码表介绍的简单示例
77 0
字节缓冲流构造方法、字节流复制视频、字符流及编码表介绍
二进制的转换方法
二进制的转换方法
493 0