【发布时间】:2016-08-23 04:16:50
【问题描述】:
目前在我的iOS应用中我使用zlib对数据进行放气,我想在Android中实现相同的逻辑,以便在这两个平台上处理的放气数据兼容并可以传输。
在下面的代码中,inputString 都是任意随机字符串,例如:
开发人员信任 Stack Overflow 可以帮助解决编码问题并使用 Stack Overflow 职业寻找工作机会。我们致力于让互联网变得更美好,我们的产品旨在丰富开发者在职业生涯中成长和成熟的生活。
在 iOS 中,使用以下代码段:
NSData *rawData = [inputString dataUsingEncoding:NSUTF8StringEncoding];
NSInputStream * src = [NSInputStream inputStreamWithData:rawData];
[src open];
NSOutputStream * dest = [NSOutputStream outputStreamToMemory];
[dest open];
int res = [self deflateDataStream:src toOutputStream:dest level:Z_DEFAULT_COMPRESSION];
[dest close];
[src close];
if (res != Z_OK) return nil;
NSData *ret = [dest propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
+ (int) deflateDataStream:(NSInputStream *)source toOutputStream:(NSOutputStream *)dest level:(int)level {
int ret, flush;
unsigned have;
z_stream strm;
unsigned char inBuf[CHUNK];
unsigned char outBuf[CHUNK];
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
ret = deflateInit2(&strm, level, Z_DEFLATED, (16+MAX_WBITS), MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
if (ret != Z_OK) return ret;
do {
NSInteger res = [source read:inBuf maxLength:CHUNK];
if (res < 0) {
NSLog(@"!!! Error reading stream: %ld %@", (long)source.streamStatus, source.streamError);
(void)deflateEnd(&strm);
return Z_ERRNO;
}
flush = [source hasBytesAvailable] ? Z_NO_FLUSH : Z_FINISH;
strm.avail_in = (uInt)res;
strm.next_in = inBuf;
do {
strm.avail_out = CHUNK;
strm.next_out = outBuf;
ret = deflate(&strm, flush);
assert(ret != Z_STREAM_ERROR);
have = CHUNK - strm.avail_out;
res = [dest write:outBuf maxLength:have];
if (res != have || res < 0) {
(void)deflateEnd(&strm);
return Z_ERRNO;
}
} while (strm.avail_out == 0);
assert(strm.avail_in == 0);
} while (flush != Z_FINISH);
assert(ret == Z_STREAM_END);
(void)deflateEnd(&strm);
return Z_OK;
}
之后,压缩数据将被进一步处理(进行加密等)并保存。
然后对于我目前正在开发的 Android 版本,从文档页面 here 中,Deflater 类使用 zlib 逻辑执行放气,所以我尝试使用以下代码段:
byte[] dataToBeDeflated = inputString.getBytes(Charset.forName("UTF-8"));
Deflater deflater = null;
ByteArrayOutputStream outputStream = null;
byte[] deflatedData = null;
try {
deflater = new Deflater();
deflater.setStrategy(Deflater.DEFAULT_STRATEGY);
deflater.setLevel(Deflater.DEFAULT_COMPRESSION);
deflater.setInput(dataToBeDeflated);
outputStream = new ByteArrayOutputStream(dataToBeDeflated.length);
deflater.finish();
byte[] buffer = new byte[1024];
while (!deflater.finished()) {
int count = deflater.deflate(buffer);
outputStream.write(buffer, 0, count);
}
deflatedData = outputStream.toByteArray();
} catch (Exception e) {
Log.e(TAG, "Deflate exception", e);
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
Log.e(TAG, "Failed to close the output stream", e);
}
}
}
但是,上述实现在 Android 上返回的结果与在 iOS 中产生的结果不同,这使得我现有的 iOS 应用程序无法使用它。
使用我引用的测试字符串,iOS 产生大小为 197 字节的NSData,其中原始字符串数据为 273 字节。虽然 Android 上的原始输入大小也是 273 字节,但上面的实现给出了大小为 185 的结果。
目前在 iOS 端更改逻辑不可行,因为这将涉及许多额外的过程,例如提交审核等。
我假设两个平台的底层算法应该是相同的?如果是这种情况,为什么结果会不同?我是否做错了什么?如何纠正它并在 Android 上获得相同的结果?
谢谢!
【问题讨论】:
标签: java android ios zlib deflate