java和C结构体通信

package com.cvicse.naba.service.impl.user;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.cvicse.naba.common.utils.ByteConvert;
import com.cvicse.naba.common.utils.ObjectUtils;
import com.cvicse.naba.service.api.msg.IMessageManSrv;
import com.cvicse.naba.service.api.user.IUserManageSrv;
import com.cvicse.unicorn.framework.entity.CB_User;

/**
 * 
 * 
 * 描述:
 * <p>
 *     用户操作数据接口实现类。
 * </p>
 * 创建日期:2012-7-9 下午3:39:46<br>
 * 
 * @author:tianyj<br>
 * @update:$Date$<br>
 * @version:$Revision$<br>
 * @since 1.0.0
 */
public class UserManageSrvImpl implements IUserManageSrv {

	private static final int STRUCTS_LENGTH = 316;

	private IMessageManSrv messageManSrv;

	/**
	 * 保存用户信息到后台
	 * 
	 * @param user
	 * 			当前登陆user对象
	 * @param map
	 * 			添加的数据信息
	 * @return boolean
	 * 			成功与否,true成功;false失败
	 * @throws Exception
	 */
	@Override
	public String saveUser(CB_User user, Map<String, String> map) throws Exception {
		// 方法坐标
		user.setC_x(20);
		user.setC_y(1);
		// 保存前台传递的用户数据信息
		// String userInfo = this.getSaveUserMessage(map);
		byte[] returnMsg = messageManSrv.exeCommand(user, getSaveUserMessage(map));
		String result = null;
		if (returnMsg != null) {
			if (handleResult(returnMsg)) {
				result = "true";
			} else {
				result = "false";
			}
		} else {
			result = "logout";
		}
		// 处理后台返回的操作结果
		return result;
	}
	
	/**
	 * 更新用户信息,
	 * 只是调用后台的方法不同 通过设置user.setC_X和user.setC_Y方法坐标确定
	 * @param user
	 *            user对象,主要是方法坐标
	 * @param map
	 *            更新的信息
	 * @return
	 * @throws Exception
	 */
	@Override
	public String updateUser(CB_User user, Map<String, String> map) throws Exception {
		user.setC_x(20);
		user.setC_y(4);
		// 更新前台需要更新的用户信息
		// String userInfo = this.getUpdateUserMessage(map);
		byte[] returnMsg = messageManSrv.exeCommand(user, getUpdateUserMessage(map));
		String result = null;
		if (returnMsg != null) {
			if (handleResult(returnMsg)) {
				result = "true";
			} else {
				result = "false";
			}
		} else {
			result = "logout";
		}
		// 处理后台操作返回的结果
		return result;
	}
	
	/**
	 * 修改用户登陆密码,没有用到暂时
	 * @param user
	 * @param map
	 * @throws Exception
	 * @return 
	 */
	@Override
    public boolean updatePassword(CB_User user, Map<String, String> map) throws Exception {
	    // TODO Auto-generated method stub
		String passInfo = "";
		byte[] returnMsg = messageManSrv.exeCommand(user, passInfo);
		// 处理后台操作返回的结果
	    return handleResult(returnMsg);
    }
	
	/**
	 * 删除用户
	 * @parma user
	 * 			当前登陆user对象
	 * @param str
	 * 			要删除的user的ID
	 * @throws Exception
	 * 			
	 * @return boolean 
	 * 			返回是否删除成功:true成功;false失败
	 */
	@Override
	public String deleteUser(CB_User user, String str) throws Exception {
		user.setC_x(20);
		user.setC_y(3);
		// 处理返回的信息
		byte[] returnMsg = messageManSrv.exeCommand(user, str);
		String result = null;
		if (returnMsg != null && handleResult(returnMsg)) {
			if (handleResult(returnMsg)) {
				result = "true";
			} else {
				result = "false";
			}
		} else {
			result = "logout";
		}
		return result;
	}
	
	/**
	 * 获得单个用户信息
	 */
	@Override
	public Map<String, String> getUserMap(CB_User user, String userID) throws Exception {
		// 处理后台传递的字符串进行解析
		Map<String, String> map = null;
		byte[] returnMsg = messageManSrv.exeCommand(user, "");
		// 处理字节转换为CB_User
		byte[] struct = new byte[returnMsg.length - 7];
		System.arraycopy(returnMsg, 7, struct, 0, returnMsg.length - 7);
		map = this.getUserInfoFromByte(struct);
		return map;
	}

	/**
	 * 返回的returnMsg格式【4个字节+1个字节+2个字节+结构体列表字节】
	 * 4个字节表示传递长度但是不包括该4个字节在内 1个字节表示成功或者失败
	 * 2个字节表示调用后台的方法坐标 结构体字节:每个结构体都是固定长度,
	 * 不足补0,需要把结构体列表 进行解析处理
	 */
	@Override
	public List<Map<String, String>> getUserListMap(CB_User user) throws Exception {	
		// 设置调用后台的方法坐标
		user.setC_x(20);
        user.setC_y(2);
		// 处理后台传递的用户信息列表
		List<Map<String, String>> list = null;
		// 执行后台程序返回结果
		byte[] returnMsg = messageManSrv.exeCommand(user, "");
		if (returnMsg != null) {
			// 后台处理成功,进行解析字符串
			if (handleResult(returnMsg)) {
				// 处理字节转换为List进行返回,returnMsg.length-7表示结构体列表长度
				byte[] structs = new byte[returnMsg.length - 7];
				// 把结构体列表信息字节复制到另外的字节数组,以便处理
				System.arraycopy(returnMsg, 7, structs, 0, returnMsg.length - 7);
				// 处理结构体数组,返回List<Map>,Map中存放一个结构体信息
				list = this.getUserInfoListFromByte(structs);
			}
		} else {
			// 处理超时登陆
			list = new ArrayList<Map<String, String>>();
			Map<String, String> map = new HashMap<String, String>();
			map.put("logout", "logout");
			list.add(map);
		}
		
		return list;
	}
	
	/**
	 * 解析后台操作的结果
	 * 
	 * @param msg
	 * @return
	 */
	private boolean handleResult(byte[] msg) {
		boolean flag = false;
		if (msg.length >= 7) {
			// 消息【4个字节+1个字节+2个字节+n个字节】
			int result = msg[4];
			if (0 == result) {
				flag = true;
			}
		}
		return flag;
	}

	/**
	 * 依赖注入IMessageManSrv
	 * 
	 * @param messageManSrv
	 */
	public void setMesageManSrv(IMessageManSrv messageManSrv) {
		this.messageManSrv = messageManSrv;
	}

	/**
	 * 释放注入的IMessageManSrv
	 * 
	 * @param messageManSrv
	 */
	public void unSetMessageManSrv(IMessageManSrv messageManSrv) {
		this.messageManSrv = null;
	}

	/**
	 * 封装后台结构体,传递给后台进行存储操作 
	 * typedef struct { 
	 * 	unsigned char cmdtype; 
	 * 	unsigned char subcmd; 
	 *  unsigned char operate; //1.add, 2.change添加、修改 
	 *  unsigned char passflag;//是否采用USB-KEY方式登录 
	 *  unsigned char priority; 
	 *  unsigned char state;---//状态,禁用与否 
	 *  空两个字节
	 *  int permission; 
	 *  int authtype; 
	 *  unsigned char userid[16];//用户ID 
	 *  unsigned char username[16];//用户名
	 *  unsigned char passfirst[16];//密码 
	 *  unsigned char passsecond[16]; 
	 *  unsigned char emailaddr[64];//邮箱 
	 *  unsigned char dept[32];//部门
	 *  unsigned char mobile[16];//电话
	 * 	unsigned char role[16];//角色 
	 * 	unsigned char memo[128];//描述 
	 * } PKT_USER_REQ;
	 * 
	 * @param map
	 * @return
	 */
	private byte[] getSaveUserMessage(Map<String, String> map) {
		/*StringBuffer msg = new StringBuffer();*/
		byte[] msgByte = new byte[336];
		
		byte[] preSixMsg = new byte[6];
		preSixMsg[0] = 0;// cmdtype
		preSixMsg[1] = 0;// subcmd
		preSixMsg[2] = 1;// operate 1.add, 2.change添加、修改
		// passflag是否采用USB-KEY方式登录
		preSixMsg[3] = Byte.parseByte(ObjectUtils.toString(map.get("isUkey")));
		preSixMsg[4] = 0;// priority

		// state状态,禁用与否
		preSixMsg[5] = Byte.parseByte(ObjectUtils.toString(map.get("state")));
		System.arraycopy(preSixMsg, 0, msgByte, 0, preSixMsg.length);
		
		// 补零操作
		byte[] completeZero = {0,0};
		System.arraycopy(completeZero, 0, msgByte, 6, completeZero.length);
		
		byte[] permissionByte = ByteConvert.intToLBytes(
				Integer.parseInt(ObjectUtils.toString(map.get("permission"))));//{0, 0, 0, 0};
		System.arraycopy(permissionByte, 0, msgByte, 8, permissionByte.length);
		
		// permissionByte[0] = Byte.parseByte(ObjectUtils.toString(map.get("permission")),2);
		byte[] authtypeByte = {0, 0, 0, 0};
		System.arraycopy(authtypeByte, 0, msgByte, 12, authtypeByte.length);
		
		// 用户ID构造字节数组,不足16个字节补0
		byte[] userid = new byte[16];
		userid = buildByteArray(ObjectUtils.toString(map.get("userId")).getBytes(), userid);
		System.arraycopy(userid, 0, msgByte, 16, userid.length);
		
		// 用户名字节数组,不足16个字节补0
		byte[] username = new byte[16];
		username = buildByteArray(ObjectUtils.toString(map.get("userName")).getBytes(), username);
		System.arraycopy(username, 0, msgByte, 32, username.length);

		// 密码字节数组,不足16个字节补0
		byte[] passfirst = new byte[16];
		passfirst = buildByteArray(ObjectUtils.toString(map.get("password")).getBytes(), passfirst);
		System.arraycopy(passfirst, 0, msgByte, 48, passfirst.length);
		
		// 二次密码
		byte[] passsecond = new byte[16];
		passsecond = buildByteArray(ByteConvert.intToBytes(0), passsecond);
		System.arraycopy(passsecond, 0, msgByte, 64, passsecond.length);

		// 邮箱字节数组,不足64个字节补0
		byte[] emailaddr = new byte[64];
		emailaddr = buildByteArray(ObjectUtils.toString(map.get("email")).getBytes(), emailaddr);
		System.arraycopy(emailaddr, 0, msgByte, 80, emailaddr.length);
		
		// 部门字节数组,不足32个字节补0
		byte[] dept = new byte[32];
		dept = buildByteArray(ObjectUtils.toString(map.get("dept")).getBytes(), dept);
		System.arraycopy(dept, 0, msgByte, 144, dept.length);
		
		// 电话
		byte[] mobile = new byte[16];
		mobile = buildByteArray(ObjectUtils.toString(map.get("mobile")).getBytes(), mobile);
		System.arraycopy(mobile, 0, msgByte, 176, mobile.length);
		
		// 角色
		byte[] role = new byte[16];
		role = buildByteArray(ObjectUtils.toString(map.get("role")).getBytes(), role);
		System.arraycopy(role, 0, msgByte, 192, role.length);
		
		// 描述
		byte[] memo = new byte[128];
		memo = buildByteArray(ObjectUtils.toString(map.get("memo")).getBytes(), memo);
		System.arraycopy(memo, 0, msgByte, 208, memo.length);
		/*msg.append(ChangeCharSet.toUTF8(preSixMsg))
			.append(ChangeCharSet.toUTF8(completeZero))
			.append(ChangeCharSet.toUTF8(permissionByte))
		    .append(ChangeCharSet.toUTF8(authtypeByte))
		    .append(ChangeCharSet.toUTF8(userid))
		    .append(ChangeCharSet.toUTF8(username))
		    .append(ChangeCharSet.toUTF8(passfirst))
		    .append(ChangeCharSet.toUTF8(passsecond))
		    .append(ChangeCharSet.toUTF8(emailaddr))
		    .append(ChangeCharSet.toUTF8(dept))
		    .append(ChangeCharSet.toUTF8(mobile))
		    .append(ChangeCharSet.toUTF8(role))
		    .append(ChangeCharSet.toUTF8(memo));*/

		return msgByte;
	}

	/**
	 * typedef struct {
     *	unsigned char cmdtype;
     *	unsigned char subcmd;
     *	unsigned char userid[USER_NAME_SIZE];
     *	unsigned char chpass; //0:不修改  1:修改
     *	unsigned char oldpass[USER_PASS_SIZE];
     *	unsigned char newpass[USER_PASS_SIZE];
     *	unsigned char passflag;
     *	unsigned char priority;
     *	unsigned char state;
     *	int permission;
     *	int authtype;
     *	unsigned char username[USER_NAME_SIZE];
     *	unsigned char passfirst[USER_PASS_SIZE];
     *	unsigned char passsecond[USER_PASS_SIZE];
     *	unsigned char emailaddr[USER_MAIL_SIZE];
     *	unsigned char dept[32];
     *	unsigned char mobile[USER_TLE_SIZE];
     *  unsigned char role[USER_ROLE_SIZE];
     *	unsigned char memo[USER_MEMO_LEN];
	 * } PKT_EDIT_USER_REQ ;
	 * 
	 * @param map
	 * @return
	 */
	private byte[] getUpdateUserMessage(Map<String, String> map){
		// StringBuffer msg = new StringBuffer();
		byte[] msgByte = new byte[368];
		
		byte[] preTwo = new byte[2];
		preTwo[0] = 0;
		preTwo[1] = 0;
		System.arraycopy(preTwo, 0, msgByte, 0, preTwo.length);
		
		// 用户ID构造字节数组,不足16个字节补0
		byte[] userid = new byte[16];
		userid = buildByteArray(ObjectUtils.toString(map.get("userId")).getBytes(), userid);
		System.arraycopy(userid, 0, msgByte, 2, userid.length);
		
		// 是否修改密码
		byte[] chpass = new byte[1];
		chpass[0] = Byte.parseByte(ObjectUtils.toString(map.get("chpass")));
		System.arraycopy(chpass, 0, msgByte, 18, chpass.length);
		
		// 旧密码
		byte[] oldPass = new byte[16];
		// 新密码
		byte[] newPass = new byte[16];
		// 修改密码为1
		if ("1".equals(ObjectUtils.toString(map.get("chpass")))) {
			oldPass = buildByteArray(ObjectUtils.toString(map.get("oldPass")).getBytes(), oldPass);
			newPass = buildByteArray(ObjectUtils.toString(map.get("newPass")).getBytes(), newPass);
		} 
		System.arraycopy(oldPass, 0, msgByte, 19, oldPass.length);
		System.arraycopy(newPass, 0, msgByte, 35, newPass.length);
		
		// 是否使用ukey
		byte[] passflag = new byte[1];
		passflag[0] = Byte.parseByte(ObjectUtils.toString(map.get("isUkey")));
		System.arraycopy(passflag, 0, msgByte, 51, passflag.length);
		
		// priority,无用
		byte[] priority = {0};
		System.arraycopy(priority, 0, msgByte, 52, priority.length);
		
		// 用户状态,是否被禁用
		byte[] state = new byte[1];
		state[0] = Byte.parseByte(ObjectUtils.toString(map.get("state")));
		System.arraycopy(state, 0, msgByte, 53, state.length);
		
		// 补零
		byte[] completeZero = {0, 0};
		System.arraycopy(completeZero, 0, msgByte, 54, completeZero.length);
		
		// 无用
		byte[] permissionByte = ByteConvert.intToLBytes(
				Integer.parseInt(ObjectUtils.toString(map.get("permission"))));
		System.arraycopy(permissionByte, 0, msgByte, 56, permissionByte.length);
		
		byte[] authtypeByte = {0, 0, 0, 0};
		System.arraycopy(authtypeByte, 0, msgByte, 60, authtypeByte.length);
		
		// 用户名字节数组,不足16个字节补0
		byte[] username = new byte[16];
		username = buildByteArray(ObjectUtils.toString(map.get("userName")).getBytes(), username);
		System.arraycopy(username, 0, msgByte, 64, username.length);
		
		// 密码字节数组,不足16个字节补0,不用
		byte[] passfirst = new byte[16];
		passfirst = buildByteArray(ByteConvert.intToBytes(0), passfirst);
		System.arraycopy(passfirst, 0, msgByte, 80, passfirst.length);
		
		// 二次密码,不用
		byte[] passsecond = new byte[16];
		passsecond = buildByteArray(ByteConvert.intToBytes(0), passsecond);
		System.arraycopy(passsecond, 0, msgByte, 96, passsecond.length);
		
		// 邮箱字节数组,不足64个字节补0
		byte[] emailaddr = new byte[64];
		emailaddr = buildByteArray(ObjectUtils.toString(map.get("email")).getBytes(), emailaddr);
		System.arraycopy(emailaddr, 0, msgByte, 112, emailaddr.length);
		
		// 部门字节数组,不足32个字节补0
		byte[] dept = new byte[32];
		dept = buildByteArray(ObjectUtils.toString(map.get("dept")).getBytes(), dept);
		System.arraycopy(dept, 0, msgByte, 176, dept.length);
		
		// 电话
		byte[] mobile = new byte[16];
		mobile = buildByteArray(ObjectUtils.toString(map.get("mobile")).getBytes(), mobile);
		System.arraycopy(mobile, 0, msgByte, 208, mobile.length);
		
		// 角色
		byte[] role = new byte[16];
		role = buildByteArray(ObjectUtils.toString(map.get("role")).getBytes(), role);
		System.arraycopy(role, 0, msgByte, 224, role.length);
		
		// 描述
		byte[] memo = new byte[128];
		memo = buildByteArray(ObjectUtils.toString(map.get("memo")).getBytes(), memo);
		System.arraycopy(memo, 0, msgByte, 240, memo.length);
		
		/*msg//.append(ChangeCharSet.toUTF8(preTwo))
			.append(ChangeCharSet.toUTF8(userid))
			.append(ChangeCharSet.toUTF8(chpass))
			.append(ChangeCharSet.toUTF8(oldPass))
			.append(ChangeCharSet.toUTF8(newPass))
			.append(ChangeCharSet.toUTF8(passflag))
			.append(ChangeCharSet.toUTF8(priority))
			.append(ChangeCharSet.toUTF8(state))
			.append(ChangeCharSet.toUTF8(completeZero))
			.append(ChangeCharSet.toUTF8(permissionByte))
			.append(ChangeCharSet.toUTF8(authtypeByte))
			.append(ChangeCharSet.toUTF8(username))
			.append(ChangeCharSet.toUTF8(passfirst))
			.append(ChangeCharSet.toUTF8(passsecond))
			.append(ChangeCharSet.toUTF8(emailaddr))
			.append(ChangeCharSet.toUTF8(dept))
			.append(ChangeCharSet.toUTF8(mobile))
			.append(ChangeCharSet.toUTF8(role))
			.append(ChangeCharSet.toUTF8(memo));*/
	
		return msgByte;
	}
	
	/**
	 * 拷贝字节数组,不足长度补0,0的编码为48;
	 * 
	 * @param srcArry
	 * @param destArry
	 * @param length
	 * @return
	 */
	private byte[] buildByteArray(byte[] srcArry, byte[] destArry) {
		int length = srcArry.length;
		if (srcArry.length > destArry.length) {
			length = destArry.length;
		}
		System.arraycopy(srcArry, 0, destArry, 0, length);
		return destArry;
	}

	/**
	 * 处理后台传递过来的多个结构体的方法,固定一个结构体的长度为313个字节 把结构体数组字节分割成单个结构体数组,然后进行对每个结构体数组进行
	 * 解析,存放到Map中,Map中对应的是一个结构体,也就是用户信息
	 * 
	 * @param structs
	 *            结构体列表字节数组
	 * @return
	 */
	private List<Map<String, String>> getUserInfoListFromByte(byte[] structs) throws Exception {
		List<Map<String, String>> list = new ArrayList<Map<String, String>>();
		// 把结构体字节数组进行分割成多个结构体
		for (int i = 0; i < structs.length / STRUCTS_LENGTH; i++) {
			// 复制到新的byte数组
			byte[] struct = new byte[STRUCTS_LENGTH];
			// 在原数组复制操作的起始位置
			int srcPosition = i * STRUCTS_LENGTH;
			System.arraycopy(structs, srcPosition, struct, 0, STRUCTS_LENGTH);
			// 解析单个结构体
			Map<String, String> temp = getUserInfoFromByte(struct);
			list.add(temp);
		}
		return list;
	}

	/**
	 * 请求返回的用户列表结构体定义 
	 * typedef struct { 
	 * 0 unsigned char passflag; // 是否启用UKey
	 * 1 unsigned char priority; 
	 * 2 unsigned char state; 
	 * 3 unsigned char reserve; 
	 * 4 unsigned char authtype; 
	 * 5 unsigned char userid[16]; 
	 * 21 unsigned char username[16]; 
	 * 37 unsigned char emailaddr[64]; 
	 * 101 unsigned char dept[32]; 
	 * 133 unsigned char mobile[16];
	 * 149 unsigned char role[16]; 
	 * 168 int permission; 
	 * 172 unsigned int createtime;
	 * 176 unsigned int lasttime; 
	 * 180 int logintimes; 
	 * 184 int failtimes; 181 unsigned
	 * 188 char memo[128]; 185 } PKT_USER_LIST;
	 * 
	 * @param struct
	 * @return
	 * @throws Exception
	 */
	private Map<String, String> getUserInfoFromByte(byte[] struct) throws Exception {
		Map<String, String> map = new HashMap<String, String>();
		map.put("isUkey", String.valueOf(struct[0]));
		map.put("state", String.valueOf(struct[2]));
		map.put("userId", getFieldValue(struct, 5, 16, "string"));
		map.put("userName", getFieldValue(struct, 21, 16, "string"));
		map.put("email", getFieldValue(struct, 37, 64, "string"));
		map.put("dept", getFieldValue(struct, 101, 32, "string"));
		map.put("mobile", getFieldValue(struct, 133, 16, "string"));
		map.put("role", getFieldValue(struct, 149, 16, "string"));
		map.put("permission", getFieldValue(struct, 168, 4, "integer"));
		map.put("createtime", getFieldValue(struct, 172, 4, "time"));
		map.put("lasttime", getFieldValue(struct, 176, 4, "time"));
		map.put("logintimes", getFieldValue(struct, 180, 4, "integer"));
		map.put("failtimes", getFieldValue(struct, 184, 4, "integer"));
		map.put("memo", getFieldValue(struct, 188, 128, "string"));
		return map;
	}

	/**
	 * 处理结构体中单个数据, 从给定的字节数组中取出特定位置的字节转换为字符串
	 * 
	 * @param bty
	 * @param srcPosition
	 * @param length
	 * @return
	 */
	private String getFieldValue(byte[] bty, int srcPosition, int length, String converFlag) throws Exception {
		// 拷贝规定的字节长度
		byte[] temp = new byte[length];
		String returnStr = "";
		System.arraycopy(bty, srcPosition, temp, 0, length);
		if ("".equals(converFlag) || "string".equals(converFlag)) {
			// 记录有效字节的长度
			int position = 0;
			/*
			 * 字节数组从后面截取,到第一个不为0停止,记录位置,0-position为有效字节
			 * 例子:[12,52,89,0,0,0,0],有效字节为前面的非0字节
			 */
			for (int i = temp.length - 1; i >= 0; i--) {
				position = i;
				if (temp[i] != 0) {
					break;
				}
			}
			// 把有效字节转为为字符串
			byte[] validValue = new byte[position + 1];
			System.arraycopy(temp, 0, validValue, 0, position + 1);
			returnStr = new String(validValue);
		} else if ("time".equals(converFlag)) {
			long time = ByteConvert.lBytesToInt(temp);
			returnStr = ObjectUtils.get24Time(time*1000);
			/*Date date = new Date(time*1000);
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			returnStr = sdf.format(date);*/
		} else if ("integer".equals(converFlag)) {
			returnStr = String.valueOf(ByteConvert.lBytesToInt(temp));
		}
		
		return returnStr;
	}

}

PS:

1、C中int类型的数据在内存中存放和int类型占用的字节数有关,因此有些地方需要补零操作。例如,C在系统中占用4个字节,int类型的数据在内存中存放开始字节是被4整除的地址,通过socket传递过来的字节数组在相应的位置会进行补零(C端进行操作),在Java中解析字节时或者构造相应的结构体字节数组时都要对补零的地方进行操作,去掉补充的零占位字节或者添加相应的补零操作,然后进行传递。

2、在C中的字符串会有结束标识"\0",从Java端传递的数据不要占满整个字节数组,例如:unsigned char emailaddr[64],java字节数组如果填充满了该字符数组,C进行构造该字节数组时会舍去一部分,会造成乱码。注意操作




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值