在上一篇文章(利用C#改写JAVA中的Base64.DecodeBase64以及Inflater解码),我已经提到,目前的项目需要进行平台移植,即JAVA平台服务迁移到DotNet平台服务中,服务是用来和公司的一款终端设备产品进行数据传输与交换。
如图,这个终端产品用于与终端接口进行TCP对接。而终端接口(也就是我现在要讨论的平台服务)。
1. 在上一篇文章中,我使用了ICSharpCode.SharpZipLib.dll组件,对于进行数据压缩以及解压,首先JAVA平台服务中利用log4j组件产生日志文件,查看其中一个日志文件的某一片段:
这个是终端设备通过JAVA平台服务请求一个商户信息时候,返回的一个HTTP反馈数据,可以看到HTTP反馈包包括两方面内容,一个是数据头,一个是数据体,数据体是一个base64的编码:
eJwzMAADI3MgYWhgZGAIJIxMDY0NLQ0sjPQMEMDQVEFB4eyPrY+NjBTIAsGGRpYGBmZG5oZAky1I13/xwvZF1y5cOEKe7cQBAPx4Lgo=
JAVA平台服务通过代码:
String str
=
"
……
"
;
new
String(ZipUtil.decompressByteArray(Base64.decodeBase64(str.getBytes())));
进行数据体解压。
2. 在.NET中,我利用ICSharpCode.SharpZipLib组件进行数据体解压。
解压方法为:
解压代码
private
static
string _Decompress(
byte
[] bytes)
{
string resultStr
=
string.Empty;
using (MemoryStream memoryStream
=
new
MemoryStream(bytes))
{
using (SharpZipLibStreams.InflaterInputStream stream
=
new
SharpZipLibStreams.InflaterInputStream(memoryStream))
{
using (MemoryStream buffer
=
new
MemoryStream())
{
byte
[] result
=
new
byte
[
1024
];
int
resLen;
while
((resLen
=
stream.Read(result,
0
, result.Length))
>
0
)
{
buffer.Write(result,
0
, resLen);
}
byte
[] byteDest
=
buffer.ToArray();
resultStr
=
Encoding.Default.GetString(buffer.ToArray(),
0
, byteDest.Length);
}
}
}
return
resultStr;
}
调用方法:
string
baseStr1
=
"
eJwzMAADI3MgYWhgZGAIJIxMDY0NLQ0sjPQMEMDQVEFB4eyPrY+NjBTIAsGGRpYGBmZG5oZAky1I13/xwvZF1y5cOEKe7cQBAPx4Lgo=
"
;
string
str1
=
ZipUtil.Decompress(baseStr1, ZipType.SharpZipLib);
Console.WriteLine(str1);
运行结果:
数据体解压后的数据是正确的。得出来的结果令我挺开心的,完成了第一步。
那么好了,我现在想继续对这个字符串压缩,看能否得到刚才的BASE64编码字符串。
压缩方法为:
压缩代码
private
static
byte
[] _Compress(
string
str)
{
byte
[] bytes
=
Encoding.Default.GetBytes(str);
using
(MemoryStream memoryStream
=
new
MemoryStream())
{
using
(SharpZipLibStreams.DeflaterOutputStream stream
=
new
SharpZipLibStreams.DeflaterOutputStream(memoryStream))
{
stream.Write(bytes,
0
, bytes.Length);
}
return
memoryStream.ToArray();
}
}
调用方法:
string
str2
=
ZipUtil.Compress(str1, ZipType.SharpZipLib);
Console.WriteLine(str2);
再运行结果:
发现这个字符串和原来的BASE64字符串的内容不一样。对于这个方法自己也折腾了挺久,始终无法得到正确的字符串。后来使用这个得出来的字符串,再进行解码,得到的也是以下的字符串:
(PS:自己实在没有办法,如果大家有什么可以解决的办法,不凡告知我一下,谢谢大家!)
3. 后来对于这个原始字符串进行了分析,首先我在VS2010下,编写测试代码:
string
s1
=
"
00000002700010201102251319082.0000000000015 网点22 S1290062710828 研发中心
"
;
byte
[] bytes
=
Encoding.Default.GetBytes(s1);
for
(
int
i
=
0
; i
<
bytes.Length; i
++
)
{
Console.Write(bytes[i]
+
"
,
"
);
}
运行结果:
接着我在Eclipse平台下,编写代码:
String s1
=
"
00000002700010201102251319082.0000000000015 网点22 S1290062710828 研发中心
"
;
byte
[] b1
=
s1.getBytes();
for
(
int
i
=
0
; i
<
b1.length; i
++
)
{
System.out.print(b1[i]
+
"
,
"
);
}
运行结果:
为什么这里不一样呢?哦,问题就在这里,在JAVA中的byte类型,是有符号的整型类型,相当于C#中的sbyte类型。
而C#中的byte是无符号的整型类型,它的范围为0-255之间,即无符号8位整数,因此相对于byte类型的sbyte类型,应当将byte的整型值全部减去256,请对比两张图,可以发现205-256=-51,满足了要求。
但是对于ICSharpCode.SharpZipLib组件,没有方法可以对sbyte类型进行解压以及压缩操作。虽然通过分析ICSharpCode.SharpZipLib源代码,可以解决。但是这样让工作更复杂化。
4. 最后,想起来了J#类库中包括对于JAVA类库的使用,这些类库是微软对于JAVA包的二次封装。(你可以通过安装VS2005获得这些包,也就是DLL,目录默认在:C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727中),见如下:
如果你的开发环境没有安装VS2005,也没有关系,你可以把这里的DLL文件引用到你的项目中,主要引用vjslib.dll以及vjsnativ.dll,vjsnativ.dll是个COM组件,所以你可以把它的dll的属性修改设置:
这样你就可以在VS2010开发环境下使用具有JAVA包的C#类库。
使用命名空间:
using
java.io;
using
java.util.zip;
压缩以及解压的代码如下:
压缩代码:
压缩代码
private
static
sbyte
[] _CompressString(
string
str)
{
Deflater f
=
new
Deflater();
byte
[] bs
=
Encoding.Default.GetBytes(str);
sbyte
[] sBytes
=
ByteToSByte(bs);
f.setLevel(
-
1
);
f.setInput(sBytes);
f.finish();
ByteArrayOutputStream o
=
new
ByteArrayOutputStream(sBytes.Length);
try
{
sbyte
[] buf
=
new
sbyte
[
1024
];
while
(
!
f.finished())
{
int
got
=
f.deflate(buf);
o.write(buf,
0
, got);
}
}
finally
{
o.close();
}
return
o.toByteArray();
}
解压代码:
解压代码
public
static
string
_DecompressString(
sbyte
[] sBytes)
{
Inflater f
=
new
Inflater();
f.setInput(sBytes);
ByteArrayOutputStream o
=
new
ByteArrayOutputStream(sBytes.Length);
try
{
sbyte
[] buf
=
new
sbyte
[
1024
];
while
(
!
f.finished())
{
int
got
=
f.inflate(buf);
o.write(buf,
0
, got);
}
}
finally
{
o.close();
}
byte
[] decompessBytes
=
SByteToByte(o.toByteArray());
return
Encoding.Default.GetString(decompessBytes);
}
调用方法:
string
baseStr1
=
"
eJwzMAADI3MgYWhgZGAIJIxMDY0NLQ0sjPQMEMDQVEFB4eyPrY+NjBTIAsGGRpYGBmZG5oZAky1I13/xwvZF1y5cOEKe7cQBAPx4Lgo=
"
;
string
str1
=
ZipUtil.Decompress(baseStr1, ZipType.JSharp);
Console.WriteLine(str1);
string
str2
=
ZipUtil.Compress(str1, ZipType.JSharp);
Console.WriteLine(str2);
运行结果:
从运行结果上看,最后得到的BASE64字符串与原来的BASE64字符串保持一致了。
这样我就利用J#类库解决了项目中数据压缩以及解压的问题。有人可能要问我为什么要使用这样的一个解码规则呢?因为终端设备的程序已经固化在终端设备中了,它产生的HTTP数据头以及数据体,具有一定的规则,所以作为平台服务端,必须遵循这个规则来执行。
本篇文章作为一个分析项目中一些问题的思路,希望能够给大家带来些帮助吧!
附上本篇文章的源代码:JavaZipDemo.rar