字符串与字节的相互转换

在某A项目中,需要使用第三方系统socket接口,但第三系统无法提供接口定义。

过程中,采用方法:使用抓包工具Wireshark抓tcp包,分析抓取报文;通过报文分析接口逆向分析接口定义。(项目风险可想而知)

抓包工具抓取的都是16进制、2进制字节报文,由此引发字节与字符串互转方式的实验。

示例,源码:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;

public class TestUtf8 {

	public static void main(String[] args) throws Exception {
		final String ENCODING = "GBK";

		System.out.println("运行jdk环境的编码   =   " +  System.getProperty("file.encoding") );
		System.out.println("字符串<->字节byte 编码   =   " +  ENCODING );

		/** 测试1,字符串 转 字节**/
		String testString = "Hello汉字";
		String byteHexStr = testStringToBytes(testString, ENCODING);

		/** 测试2,字节(16进制) 转 字符串 **/
		testBytesHexToString(byteHexStr, ENCODING);
	}

	public static String testStringToBytes(final String str, final String ENCODING) throws Exception {
		System.out.println("//==========================================================");
		System.out.println("// 测试1,字符串 转 字节,字符集 = " + ENCODING);
		System.out.println("//       字符串 = " + str);
		System.out.println("//       字符集编码 = " + ENCODING);
		System.out.println("//==========================================================");

		byte[] bytes = str.getBytes(ENCODING);
		StringBuilder byteHexSB = new StringBuilder();

		MyTable table = new MyTable();
		table.addRow("byte.index", "10.value", "16.value", "2.value");
		for (int i = 0; i < bytes.length; i++) {
			byte b = bytes[i];

			int byteVal = b & 0xFF; // 一个byte占1个字节,0xFF是16进制也代表8位==1个字节,位于操作可以防止出现负数。

			String byteHexString = convertHexStringFromByte(b);
			String byteBinaryString = convertBinaryStringFromByte(b);

			byteHexSB.append(byteHexString);

			table.addRow(""+i, ""+byteVal, byteHexString, byteBinaryString);
		}
		table.printTable();

		// 字符串的字节数组,16进制表示。字符串中2位代表一个字节byte
		return byteHexSB.toString();
	}

	public static void testBytesHexToString(final String byteHexStr, final String ENCODING) throws Exception {
		System.out.println("//==========================================================");
		System.out.println("// 测试2,字节(16进制) 转 字符串,字符集 = " + ENCODING);
		System.out.println("//       16进制byte = " + byteHexStr);
		System.out.println("//       字符集编码 = " + ENCODING);
		System.out.println("//==========================================================");
		byte[] convertByte= convertByteFromHex(byteHexStr);
		String newString = new String(convertByte, ENCODING);
		System.out.println("	转换为字符串:" + newString);
		System.out.println();
	}

	/**
	 * @param byteHexString
	 * @return 将16进制记录下的byte流,翻译成byte[]数组
	 */
	public static byte[] convertByteFromHex(String byteHexString) {
		List<Byte> list = new ArrayList<>();
		int index = 0;
		while(index < byteHexString.length() - 1) {
			byte b = Integer.valueOf(byteHexString.substring(index, index + 2 ), 16).byteValue();
			list.add(b);

			index += 2;
		}

		byte[] ret = new byte[list.size()];
		IntStream.range(0, list.size()).forEach(i -> {
			ret[i] = list.get(i);
		});
		return ret;
	}

	/**
	 * @Description: 字节转成二进制字符串
	 */
	public static String convertBinaryStringFromByte(byte b) {

		int byteVal = b & 0xFF; // 一个byte占1个字节,0xFF是16进制也代表8位==1个字节,位于操作可以防止出现负数。

		String byteBinaryString = Integer.toBinaryString(byteVal);
		byteBinaryString = flushLeft('0', 16, byteBinaryString);

		return byteBinaryString;
	}

	/**
	 * @Description: 字节转成十六进制字符串
	 * @param b
	 */
	public static String convertHexStringFromByte(byte b) {

		int byteVal = b & 0xFF; // 一个byte占1个字节,0xFF是16进制也代表8位==1个字节,位于操作可以防止出现负数。

		String byteHexString = Integer.toHexString(byteVal); // byte整数值得16进制表达,不够2位前面补0
		byteHexString = flushLeft('0', 2, byteHexString);

		return byteHexString;
	}

	/**
	 * @Description: 左侧不足位 补位
	 * @param c 不足时补位的内容
	 * @param length 补位后的新字符串长度
	 * @param content 待补位的原始字符串
	 */
	private static String flushLeft(char c, int length, String content) {
		int contentLengh = content.length();

		if(contentLengh >= length) {
			return content;
		}
		StringBuilder sb = new StringBuilder();
		IntStream.range(0, length - contentLengh).forEach(i -> {
			sb.append(c);
		});
		sb.append(content);
		return sb.toString();
	}


	static class MyTable {
		private int columnSize;
		private List<List<String>> rows = new ArrayList<>();
		private List<Integer> columnSizeList = new ArrayList<>();

		public void addRow(String... column) {
			if (columnSize == 0) {
				columnSize = column.length;
			}

			if(columnSize != column.length) {
				throw new RuntimeException(String.format("列数不一致%d != %d ", columnSize, column.length));
			}

			List<String> row = Arrays.asList(column);
			rows.add(row);

			if(columnSizeList.isEmpty()) {
				IntStream.range(0, columnSize).forEach(i -> {
					int curSize = column[i].length();
					columnSizeList.add(curSize);
				});
			}else if(!columnSizeList.isEmpty()) { // 更新每列的宽度
				IntStream.range(0, columnSize).forEach(i -> {
					int curSize = column[i].length();

					if(columnSizeList.get(i) < curSize) {
						columnSizeList.set(i, curSize);
					}
				});
			}
		}
		public void printTable() {
			rows.stream().forEach( row -> {
				System.out.println(rendderRow(row));
			});
			System.out.println();
		}
		private String rendderRow(List<String> row) {
			int addSize = 2;
			StringBuilder sb = new StringBuilder();

			sb.append("	|");

			IntStream.range(0, columnSize).forEach(i -> {
				String column = row.get(i);
				String newColumnContent = flushLeft(' ', addSize + columnSizeList.get(i), column);
				sb.append(newColumnContent)
					.append(" |" );
			});

			return sb.toString();
		}
	}
}

运行结果:

运行jdk环境的编码   =   UTF-8
字符串<->字节byte 编码   =   UTF-8
//==========================================================
// 测试1,字符串 转 字节,字符集 = UTF-8
//       字符串 = Hello汉字
//       字符集编码 = UTF-8
//==========================================================
	|  byte.index |  10.value |  16.value |           2.value |
	|           0 |        72 |        48 |  0000000001001000 |
	|           1 |       101 |        65 |  0000000001100101 |
	|           2 |       108 |        6c |  0000000001101100 |
	|           3 |       108 |        6c |  0000000001101100 |
	|           4 |       111 |        6f |  0000000001101111 |
	|           5 |       230 |        e6 |  0000000011100110 |
	|           6 |       177 |        b1 |  0000000010110001 |
	|           7 |       137 |        89 |  0000000010001001 |
	|           8 |       229 |        e5 |  0000000011100101 |
	|           9 |       173 |        ad |  0000000010101101 |
	|          10 |       151 |        97 |  0000000010010111 |
//==========================================================
// 测试2,字节(16进制) 转 字符串,字符集 = UTF-8
//       16进制byte = 48656c6c6fe6b189e5ad97
//       字符集编码 = UTF-8
//==========================================================
	转换为字符串:Hello汉字

 

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值