对端是WinCE,传输struct结构体内存数据的字节流(类似这样将struct结构数据保存到文件中)。这边是java,需要读取并用类似方式回传数据。
考虑了一下,有两种解决思路:
本文最终选择了后者实现了处理。
我们碰到的struct结构类似这样:
#define STAFF_ITEM_MAX_LEN (63)
typedef struct _STAFF_INFO_T
{
DWORD dwStaffID;
TCHAR szTitle[STAFF_ITEM_MAX_LEN + 1];
TCHAR szName[STAFF_ITEM_MAX_LEN + 1];
} STAFF_INFO, * PSTAFF_INFO;
typedef const PSTAFF
对端的c处理代码:
STAFF_INFO stf1 = { 0 };
STAFF_INFO stf2 = { 0 };
stf1.dwStaffID = 0×12345678;
_tcscpy_s(stf1.szName, STAFF_ITEM_MAX_LEN, _T("Staff Name"));
_tcscpy_s(stf1.szTitle, STAFF_ITEM_MAX_LEN, _T("Staff Title"));
stf2.dwStaffID = 0xABCDEF00;
_tcscpy_s(stf2.szName, STAFF_ITEM_MAX_LEN, _T("Staff 名称"));
_tcscpy_s(stf2.szTitle, STAFF_ITEM_MAX_LEN, _T("Staff 头衔"));
FILE * pf = fopen("R:\\staff_sample.dat", "wb");
if( NULL != pf )
{
fwrite(&stf1, 1, sizeof(stf1), pf);
fwrite(&stf2, 1, sizeof(stf2), pf);
fclose(pf);
}
这里需要处理的数据类型是2种,DWORD和TCHAR。DWORD是无符号的4字节整数,TCHAR在这里确定是Unicode,即wchar(wchar_t)。
DWORD类型如果映射到java基本型的话,只有long类型可以对应,long是8字节的有符号表示整数,DWORD是4字节表示无符号整数。其中:
因此这种转换将无法表示DWORD的最大值。
转换的原理是通过左移位运算,将4字节合并到一个long型值中,如果四字节分别是:{0×12,0×34,0×56,0×78},那么先0×12转换为0×12000000,这样它需要左移3个字节长度即3*8=24位,以此类推,然后相加,即0×12000000+0×340000+0×5600+0×78,这样就得到了0×12345678。
这里需要注意,上面说的字节数组示例是为了方便理解,实际上得到的是倒排序的,即{0×78,0×56,0×34,0×12}。
从字节数组转long的方法:
public static long dwordBytesToLong(byte[] data) {
return (data[3] << 8 * 3) + (data[2] << 8 * 2) + (data[1] << 8 )
+ data[0];
}
从long到字节数组的方法:
public static byte[] longToDword(long value){
byte[] data=new byte[4];
for(int i=0;i>(8*i));
}
return data;
}
VC里的TCHAR转换,如果无条件转换,无论是java还是*nux c都是比较麻烦的。因为TCHAR即可以是ASCII码,也可以是宽字符比如UNICODE,在*nix c中是区分的。还在这里对端肯定传的是unicode,使问题得到简化。
这里不能直接用String的参数是byte[]数组的构造方法,因为String会认为字节数组是字符集编码得到的字节,会自动用默认字符集解码,而struct的TCHAR是c从内存中直接将unicode字符的内存复制出来,就相当于把java的String字符在内存中复制下来一样。
unicode是内存中的字符表示,字符集比如GBK、UTF-8是unicode存储时的编码,二者有区别。
因为内存中unicode是两字节表示一个字符(char),因此将两个字节合并成java中的一个char,然后char数组再转换为字符串。这里要注意,java中的unicode的表示和c内存中位置颠倒,拿上面“头”字举例,字节的16进制表示是:0×5934。
转换TCHAR到字符串的代码:
public static String wcharUnicodeBytesToString(byte[] data) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < data.length; i += 2) {
if (data[i] == 0xfffffffe) {
break;
}
byte[] temp = new byte[2];
temp[0] = data[i];
temp[1] = data[i + 1];
builder.append(wcharUnicodeBytesToChar(temp));
}
return builder.toString();
}
private static char wcharUnicodeBytesToChar(byte[] data) {
char c = (char) (((data[1]) << 8 ) + data[0]);
return c;
}
将java字符串转换为TCHAR的byte数组代码:
public static byte[] stringToWcharUnicodeBytes(String value,int arraySize){
char[] valueChars=value.toCharArray();
byte[] data=new byte[arraySize*2];
Arrays.fill(data, (byte)0xFE);
for(int i=0;i>8);
}
return data;
}