java与unity3d通信之数据压缩

最近项目中java、Untiy两端通信用的json,json相对纯字节通信,数据包要大很多,这就涉及到数据压缩了。untiy客户端最早用的C#自带的压缩算法,但在untiy上用就抛出异常。而后我建议他们使用lzma开源压缩算法,原来用过,在此贴出来,记录一下。

1package com.kaka.util; 2 3import SevenZip.Compression.LZMA.Decoder; 4import SevenZip.Compression.LZMA.Encoder; 5import java.io.ByteArrayInputStream; 6import java.io.ByteArrayOutputStream; 7import java.io.IOException; 8import java.io.InputStream; 9import java.io.OutputStream; 10import java.io.UnsupportedEncodingException; 11import java.util.logging.Level; 12import java.util.logging.Logger; 13 14/** 15 * 7zip的lzma压缩,压缩比高,效率低 16 * 17 * @author zhoukai 18 */ 19public final class Lzma { 20 21 /** 22 * lzma压缩 23 * 24 * @param is 压缩输入流 25 * @param os 压缩后的输出流 26 */ 27 public final static void compress(InputStream is, OutputStream os) { 28 Encoder ec = new Encoder(); 29 try { 30 ec.WriteCoderProperties(os); 31 os.write(BitConverter.getBytes((long) is.available())); 32 ec.Code(is, os, -1, -1, null); 33 } catch (IOException ex) { 34 Logger.getLogger(Lzma.class.getName()).log(Level.SEVERE, null, ex); 35 } 36 } 37 38 /** 39 * lzma压缩 40 * 41 * @param is 压缩输入流 42 * @return 压缩后的输出流 43 */ 44 public final static byte[] compress(InputStream is) { 45 ByteArrayOutputStream os = new ByteArrayOutputStream(); 46 compress(is, os); 47 return os.toByteArray(); 48 } 49 50 /** 51 * lzma压缩 52 * 53 * @param src 压缩输入字节数组 54 * @return 压缩后的输出的字节数组 55 */ 56 public final static byte[] compress(byte[] src) { 57 return Lzma.compress(new ByteArrayInputStream(src)); 58 } 59 60 /** 61 * lzma压缩 62 * 63 * @param src 压缩输入字符串 64 * @return 压缩后的输出的字节数组 65 */ 66 public final static byte[] compress(String src) { 67 return Lzma.compress(src.getBytes(Charset.utf8)); 68 } 69 70 /** 71 * lzma压缩 72 * 73 * @param src 压缩输入字符串 74 * @param charset 字符串转字节的编码 75 * @return 压缩后的输出的字节数组 76 */ 77 public final static byte[] compress(String src, String charset) { 78 byte[] bytes = null; 79 try { 80 bytes = src.getBytes(charset); 81 } catch (UnsupportedEncodingException ex) { 82 Logger.getLogger(Lzma.class.getName()).log(Level.SEVERE, null, ex); 83 } 84 return Lzma.compress(bytes); 85 } 86 87 /** 88 * lzma压缩 89 * 90 * @param src 压缩输入字符串 91 * @param charset 字符串转字节的编码 92 * @return 压缩后的输出的字节数组 93 */ 94 public final static byte[] compress(String src, java.nio.charset.Charset charset) { 95 byte[] bytes = src.getBytes(charset); 96 return Lzma.compress(bytes); 97 } 98 99 /** 100 * lzma解压缩 101 * 102 * @param is 解压缩输入流 103 * @param os 解压缩后的输出流 104 */ 105 public final static void uncompress(InputStream is, OutputStream os) { 106 Decoder dc = new Decoder(); 107 int propertiesSize = 5; 108 byte[] properties = new byte[propertiesSize]; 109 try { 110 if (is.read(properties, 0, propertiesSize) != propertiesSize) { 111 throw new Exception("input .lzma file is too short"); 112 } 113 if (!dc.SetDecoderProperties(properties)) { 114 throw new Exception("Incorrect stream properties"); 115 } 116 byte[] outSizeBytes = new byte[8]; 117 is.read(outSizeBytes, 0, outSizeBytes.length); 118 long outSize = BitConverter.toLong(outSizeBytes, 0); 119 dc.Code(is, os, outSize); 120 } catch (Exception ex) { 121 Logger.getLogger(Lzma.class.getName()).log(Level.SEVERE, null, ex); 122 } 123 } 124 125 /** 126 * lzma解压缩 127 * 128 * @param is 解压缩输入流 129 * @return 解压缩后的输出字节数组 130 */ 131 public final static byte[] uncompress(InputStream is) { 132 ByteArrayOutputStream os = new ByteArrayOutputStream(); 133 try { 134 uncompress(is, os); 135 } catch (Exception ex) { 136 Logger.getLogger(Lzma.class.getName()).log(Level.SEVERE, null, ex); 137 } 138 return os.toByteArray(); 139 } 140 141 /** 142 * lzma解压缩 143 * 144 * @param src 解压缩输入字节数组 145 * @return 解压缩后的输出字节数组 146 */ 147 public final static byte[] uncompress(byte[] src) { 148 return Lzma.uncompress(new ByteArrayInputStream(src)); 149 } 150}

C#客户端代码

1using System; 2using System.IO; 3using SevenZip.Compression.LZMA; 4 5public class Lzma { 6 7 private static void Compress(Stream input, Stream output) 8 { 9 input.Position = 0; 10 Encoder ec = new Encoder(); 11 ec.WriteCoderProperties(output); 12 byte[] lenBytes = BitConverter.GetBytes((long)input.Length); 13 if(BitConverter.IsLittleEndian) 14 { 15 Array.Reverse(lenBytes); 16 } 17 output.Write(lenBytes, 0, lenBytes.Length); 18 ec.Code(input, output, -1, -1, null); 19 } 20 21 public static byte[] Compress(byte[] src) 22 { 23 Stream input = new MemoryStream(src); 24 Stream output = new MemoryStream(); 25 Compress(input, output); 26 output.Position = 0; 27 byte[] bytes = new byte[output.Length]; 28 output.Read(bytes, 0, bytes.Length); 29 input.Close(); 30 output.Flush(); 31 output.Close(); 32 return bytes; 33 } 34 35 public static byte[] CompressToUTF8Bytes(string src) 36 { 37 return Compress(System.Text.Encoding.UTF8.GetBytes(src)); 38 } 39 40 private static void Uncompress(Stream input, Stream output) 41 { 42 input.Position = 0; 43 Decoder dc = new Decoder(); 44 int propertiesSize = 5; 45 byte[] properties = new byte[propertiesSize]; 46 if (input.Read(properties, 0, propertiesSize) != propertiesSize) 47 { 48 throw new Exception("input .lzma file is too short"); 49 } 50 dc.SetDecoderProperties(properties); 51 byte[] outSizeBytes = new byte[8]; 52 input.Read(outSizeBytes, 0, outSizeBytes.Length); 53 if (BitConverter.IsLittleEndian) 54 { 55 Array.Reverse(outSizeBytes); 56 } 57 long outSize = BitConverter.ToInt64(outSizeBytes, 0); 58 dc.Code(input, output, -1, outSize, null); 59 } 60 61 public static byte[] Uncompress(byte[] src) 62 { 63 Stream input = new MemoryStream(src); 64 Stream output = new MemoryStream(); 65 Uncompress(input, output); 66 output.Position = 0; 67 byte[] bytes = new byte[output.Length]; 68 output.Read(bytes, 0, bytes.Length); 69 input.Close(); 70 output.Flush(); 71 output.Close(); 72 return bytes; 73 } 74 75 public static string UncompressToUTF8String(byte[] src) 76 { 77 return System.Text.Encoding.UTF8.GetString(Uncompress(src)); 78 } 79 80}

测试的时候,使用Lzma进行数据压缩压测效率不是很好,后面客户端人员发现了ICSharpCode.SharpZipLib这个库,于是又测试了一下gzip算法,还好java有点积累,工具类有现成的

1package com.kaka.util; 2 3import java.io.ByteArrayInputStream; 4import java.io.ByteArrayOutputStream; 5import java.io.IOException; 6import java.io.InputStream; 7import java.io.OutputStream; 8import java.io.UnsupportedEncodingException; 9import java.util.logging.Level; 10import java.util.logging.Logger; 11import java.util.zip.GZIPInputStream; 12import java.util.zip.GZIPOutputStream; 13 14/** 15 * GZIP压缩,压缩比相对lzma较低,但压缩效率高 16 * 17 * @author zhoukai 18 */ 19public final class GZip { 20 21 /** 22 * 压缩数据 23 * 24 * @param is 数据源 25 * @param os 压缩后的数据 26 */ 27 public final static void compress(InputStream is, OutputStream os) { 28 try (GZIPOutputStream gos = new GZIPOutputStream(os)) { 29 int count; 30 byte data[] = new byte[256]; 31 while ((count = is.read(data, 0, 256)) != -1) { 32 gos.write(data, 0, count); 33 } 34 gos.finish(); 35 gos.flush(); 36 } catch (Exception ex) { 37 Logger.getLogger(GZip.class.getName()).log(Level.SEVERE, null, ex); 38 } 39 } 40 41 /** 42 * 压缩 43 * 44 * @param src 压缩源 45 * @return 压缩后的输出的字节数组 46 */ 47 public final static byte[] compress(byte[] src) { 48 if (src == null) { 49 return null; 50 } 51 if (src.length == 0) { 52 return src; 53 } 54 byte[] bytes = null; 55 try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { 56 try (GZIPOutputStream zip = new GZIPOutputStream(out)) { 57 zip.write(src); 58 zip.finish(); 59 zip.flush(); 60 } 61 bytes = out.toByteArray(); 62 } catch (IOException ex) { 63 Logger.getLogger(GZip.class.getName()).log(Level.SEVERE, null, ex); 64 } 65 return bytes; 66 } 67 68 /** 69 * gzip压缩 70 * 71 * @param src 压缩输入字符串 72 * @param charset 字符串转字节的编码 73 * @return 压缩后的输出的字节数组 74 */ 75 public final static byte[] compress(String src, String charset) { 76 byte[] bytes = null; 77 try { 78 bytes = src.getBytes(charset); 79 } catch (UnsupportedEncodingException ex) { 80 Logger.getLogger(Lzma.class.getName()).log(Level.SEVERE, null, ex); 81 } 82 return compress(bytes); 83 } 84 85 /** 86 * gzip压缩 87 * 88 * @param src 压缩输入字符串 89 * @param charset 字符串转字节的编码 90 * @return 压缩后的输出的字节数组 91 */ 92 public final static byte[] compress(String src, java.nio.charset.Charset charset) { 93 byte[] bytes = src.getBytes(charset); 94 return compress(bytes); 95 } 96 97 /** 98 * 解压缩 99 * 100 * @param src 101 * @return 102 */ 103 public final static byte[] uncompress(byte[] src) { 104 if (src == null) { 105 return null; 106 } 107 if (src.length == 0) { 108 return src; 109 } 110 try (ByteArrayInputStream in = new ByteArrayInputStream(src)) { 111 try (GZIPInputStream zip = new GZIPInputStream(in)) { 112 byte[] bytes; 113 try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { 114 int count; 115 bytes = new byte[256]; 116 while ((count = zip.read(bytes, 0, bytes.length)) != -1) { 117 os.write(bytes, 0, count); 118 } 119 bytes = os.toByteArray(); 120 } 121 return bytes; 122 } 123 } catch (IOException ex) { 124 Logger.getLogger(GZip.class.getName()).log(Level.SEVERE, null, ex); 125 } 126 return null; 127 } 128}

C# gzip工具类

1using System.IO; 2using ICSharpCode.SharpZipLib.GZip; 3 4 5public class GZip { 6 7 public static byte[] Compress(byte[] src) 8 { 9 MemoryStream ms = new MemoryStream(); 10 GZipOutputStream gzip = new GZipOutputStream(ms); 11 gzip.Write(src, 0, src.Length); 12 gzip.Close(); 13 byte[] bytes = ms.ToArray(); 14 ms.Close(); 15 return bytes; 16 } 17 18 public static byte[] Uncompress(byte[] src) 19 { 20 MemoryStream ms = new MemoryStream(src); 21 GZipInputStream gzip = new GZipInputStream(ms); 22 MemoryStream re = new MemoryStream(); 23 int count = 0; 24 byte[] data = new byte[2048]; 25 while ((count = gzip.Read(data, 0, data.Length)) != 0) 26 { 27 re.Write(data, 0, count); 28 } 29 byte[] depress = re.ToArray(); 30 ms.Close(); 31 re.Close(); 32 gzip.Close(); 33 return depress; 34 } 35 36 public static byte[] CompressToUTF8Bytes(string src) 37 { 38 return Compress(System.Text.Encoding.UTF8.GetBytes(src)); 39 } 40 41 public static string UncompressToUTF8String(byte[] src) 42 { 43 return System.Text.Encoding.UTF8.GetString(Uncompress(src)); 44 } 45 46}
点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )