zoukankan      html  css  js  c++  java
  • 数据压缩

    转载别人的,备用。原文地址:

    再对比下: snappy

    http://www.oschina.net/p/snappy

    http://bbs.itcast.cn/thread-85176-1-1.html

    http://fengmm521.blog.163.com/blog/static/25091358201401325758620/

    http://www.cnblogs.com/zisou/p/cocos2dxJQ-8.html

    原文地址:

    因为服务器发送过的字符串比较长,加上手机用户的流量是要花钱的。所以要把服务器发送给客端的数据进行压缩。服务器端使用java自代的gzip压缩方法。而我要作的就是把这个用cocos2d-x的zlib库进行解压。在网上找了几个方法,自已都试过了。可以用。在这里记一下,方便自已以后再一次使用。

    1.用http从服务器获取压缩字符串:

    这里要在.h头文件中加入cocos2d-x的zlib库所在的头文件

    void VersionManager::testVersion()
    {

      CCHttpClient* httpClient = CCHttpClient::getInstance();

      CCHttpRequest* httpReq =new CCHttpRequest();

      httpReq->setRequestType(CCHttpRequest::kHttpGet);

      httpReq->setUrl("http://192.168.1.16:80/51256e283d370370b653ae19c12524?{'account':1234567,'stageId':1}");
      httpReq->setResponseCallback(this,httpresponse_selector(VersionManager::httpReqFinished));
      httpReq->setTag("FirstNet");
      httpClient->setTimeoutForConnect(30);
      httpClient->send(httpReq);

      httpReq->release();

    }

    void VersionManager::httpReqFinished( CCHttpClient* client, CCHttpResponse* response )
    {
     //CCHttpResponse* response = (CCHttpResponse*)obj;
     if (!response->isSucceed())
     {
      CCLog("Receive Error! %s ",response->getErrorBuffer());
      return ;
     }

     const char* tag = response->getHttpRequest()->getTag();
     if ( 0 == strcmp("FirstNet",tag))
     {
      std::vector<char> *data = response->getResponseData();
      int data_length =  data->size();
      std::string res;
      for (int i = 0;i<data_length;++i)
      {
       res+=(*data)[i];
      }
      res+='';
      //CCLog("%s",res.c_str());
      this->testVersionCallBack(res);
     }

    }

     

    //文件接收完回调
    void VersionManager::testVersionCallBack(std::string netData)
    {
     //CCLog("%s",netData.c_str());

     unsigned char xxx[segment_size];
     for (int i = 0;i< (int)netData.size()-1;i++)
     {

      xxx[i] = netData[i];
      CCLog("%x ",xxx[i]);
     }
     char out[4*segment_size];

     char* xstrout = this->ungzip(xxx,(int)netData.size()-1);
     //int eroNumber = this->ungzip(xxx,(int)(netData.size()-1),out);
     std::string outstrtmp = std::string(xstrout);
     free(xstrout);
     CCLog("out:%s",outstrtmp.c_str());

     std::string getstrxxx = this->ungZip(netData);
     CCLog("get out:%s",getstrxxx.c_str());
    }

    下边的是zlib在cocos2d-x中所在的位置:

    #include "support/zip_support/unzip.h"
    #include "support/zip_support/ZipUtils.h"

    下边是几个解压的方法:

    #define segment_size 2048 //接收的缓存,单位是字节

    char* VersionManager::ungZip(std::string source)
    {
     unsigned char xxx[segment_size];
     int len = source.size()-1;
     for (int i = 0;i< (int)source.size()-1;i++)
     {
      xxx[i] = source[i];
      //CCLog("%x ",xxx[i]);
     }

     int err;
     z_stream d_stream;
     Byte compr[segment_size]={0}, uncompr[segment_size*4]={0};
     memcpy(compr,(Byte*)xxx,len);
     //free(xxx);
     uLong comprLen, uncomprLen;
     comprLen = sizeof(compr) / sizeof(compr[0]);
     uncomprLen = 4*comprLen;
     strcpy((char*)uncompr, "garbage");

     d_stream.zalloc = (alloc_func)0;
     d_stream.zfree = (free_func)0;
     d_stream.opaque = (voidpf)0;

     d_stream.next_in = compr;
     d_stream.avail_in = 0;
     d_stream.next_out = uncompr;

     err = inflateInit2(&d_stream,47);
     if(err!=Z_OK)
     {
      printf("inflateInit2 error:%d",err);
      return NULL;
     }
     while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) {
      d_stream.avail_in = d_stream.avail_out = 1;
      err = inflate(&d_stream,Z_NO_FLUSH);
      if(err == Z_STREAM_END) break;
      if(err!=Z_OK)
      {
       printf("inflate error:%d",err);
       return NULL;
      }
     }
     err = inflateEnd(&d_stream);
     if(err!=Z_OK)
     {
      printf("inflateEnd error:%d",err);
      return NULL;
     }
     char* b = new char[d_stream.total_out+1];
     memset(b,0,d_stream.total_out+1);
     memcpy(b,(char*)uncompr,d_stream.total_out);
     return b;
    }

    下边是另外的几个参考方法:

    char* VersionManager::ungzip(unsigned char* source,int len)
    {
     int err;
     z_stream d_stream;
     Byte compr[segment_size]={0}, uncompr[segment_size*4]={0};
     memcpy(compr,(Byte*)source,len);
     uLong comprLen, uncomprLen;
     comprLen = sizeof(compr) / sizeof(compr[0]);
     uncomprLen = 4*comprLen;
     strcpy((char*)uncompr, "garbage");

     d_stream.zalloc = (alloc_func)0;
     d_stream.zfree = (free_func)0;
     d_stream.opaque = (voidpf)0;

     d_stream.next_in = compr;
     d_stream.avail_in = 0;
     d_stream.next_out = uncompr;

     err = inflateInit2(&d_stream,47);
     if(err!=Z_OK)
     {
      printf("inflateInit2 error:%d",err);
      return NULL;
     }
     while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) {
      d_stream.avail_in = d_stream.avail_out = 1;
      err = inflate(&d_stream,Z_NO_FLUSH);
      if(err == Z_STREAM_END) break;
      if(err!=Z_OK)
      {
       printf("inflate error:%d",err);
       return NULL;
      }
     }
     err = inflateEnd(&d_stream);
     if(err!=Z_OK)
     {
      printf("inflateEnd error:%d",err);
      return NULL;
     }
     char* b = new char[d_stream.total_out+1];
     memset(b,0,d_stream.total_out+1);
     memcpy(b,(char*)uncompr,d_stream.total_out);
     return b;
    }

    int VersionManager::ungzip(unsigned char* source,int len,char*des)
    {
     int ret,have;
     int offset=0;
     z_stream d_stream;
     Byte compr[segment_size]={0}, uncompr[segment_size*4]={0};
     memcpy(compr,(Byte*)source,len);
     uLong comprLen, uncomprLen;
     comprLen =len;//一开始写成了comprlen=sizeof(compr)以及comprlen=strlen(compr),后来发现都不对。

     //sizeof(compr)永远都是segment_size,显然不对,strlen(compr)也是不对的,因为strlen只算到之前,

     //但是gzip或者zlib数据里很多。
     uncomprLen = segment_size*4;
     strcpy((char*)uncompr, "garbage");

     d_stream.zalloc = Z_NULL;
     d_stream.zfree = Z_NULL;
     d_stream.opaque = Z_NULL;

     d_stream.next_in = Z_NULL;//inflateInit和inflateInit2都必须初始化next_in和avail_in
     d_stream.avail_in = 0;//deflateInit和deflateInit2则不用

     ret = inflateInit2(&d_stream,47);
     if(ret!=Z_OK)
     {
      printf("inflateInit2 error:%d",ret);
      return ret;
     }
     d_stream.next_in=compr;
     d_stream.avail_in=comprLen;
     do
     {
      d_stream.next_out=uncompr;
      d_stream.avail_out=uncomprLen;
      ret = inflate(&d_stream,Z_NO_FLUSH);
      assert(ret != Z_STREAM_ERROR);
      switch (ret)
      {
      case Z_NEED_DICT:
       ret = Z_DATA_ERROR;  
      case Z_DATA_ERROR:
      case Z_MEM_ERROR:
       (void)inflateEnd(&d_stream);
       return ret;
      }
      have=uncomprLen-d_stream.avail_out;
      memcpy(des+offset,uncompr,have);//这里一开始我写成了memcpy(des+offset,d_stream.next_out,have);

      //后来发现这是不对的,因为next_out指向的下次的输出,现在指向的是无有意义数据的内存。见下图

      offset+=have;

     }while(d_stream.avail_out==0);
     inflateEnd(&d_stream);
     memcpy(des+offset,"",1);
     return ret;
    }

    另外的两个,一个是客户端用来压缩的,和一个比较基础的解压缩方法,我都试过,这几个方法都可以正常解压和压缩。
    压缩数据:

    /* Compress gzip data */
    /* data 原数据 ndata 原数据长度 zdata 压缩后数据 nzdata 压缩后长度 */
    int VersionManager::gzcompress(Bytef *data, uLong ndata,Bytef *zdata, uLong *nzdata)
    {
     z_stream c_stream;
     int err = 0;

     if(data && ndata > 0) {
      c_stream.zalloc = NULL;
      c_stream.zfree = NULL;
      c_stream.opaque = NULL;
      //只有设置为MAX_WBITS + 16才能在在压缩文本中带header和trailer
      if(deflateInit2(&c_stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
       MAX_WBITS + 16, 8, Z_DEFAULT_STRATEGY) != Z_OK) return -1;
      c_stream.next_in  = data;
      c_stream.avail_in  = ndata;
      c_stream.next_out = zdata;
      c_stream.avail_out  = *nzdata;
      while(c_stream.avail_in != 0 && c_stream.total_out < *nzdata) {
       if(deflate(&c_stream, Z_NO_FLUSH) != Z_OK) return -1;
      }
      if(c_stream.avail_in != 0) return c_stream.avail_in;
      for(;;) {
       if((err = deflate(&c_stream, Z_FINISH)) == Z_STREAM_END) break;
       if(err != Z_OK) return -1;
      }
      if(deflateEnd(&c_stream) != Z_OK) return -1;  *nzdata = c_stream.total_out;  return 0; } return -1;}

    解决数据:

    /* Uncompress gzip data */
    /* zdata 数据 nzdata 原数据长度 data 解压后数据 ndata 解压后长度 */
    int VersionManager::gzdecompress(Byte *zdata, uLong nzdata,Byte *data, uLong *ndata)
    {
     int err = 0;
     z_stream d_stream = {0}; /* decompression stream */
     static char dummy_head[2] = {
      0x8 + 0x7 * 0x10,
      (((0x8 + 0x7 * 0x10) * 0x100 + 30) / 31 * 31) & 0xFF,
     };
     d_stream.zalloc = NULL;
     d_stream.zfree = NULL;
     d_stream.opaque = NULL;
     d_stream.next_in  = zdata;
     d_stream.avail_in = 0;
     d_stream.next_out = data;
     //只有设置为MAX_WBITS + 16才能在解压带header和trailer的文本
     if(inflateInit2(&d_stream, MAX_WBITS + 16) != Z_OK) return -1;
     //if(inflateInit2(&d_stream, 47) != Z_OK) return -1;
     while(d_stream.total_out < *ndata && d_stream.total_in < nzdata) {
      d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */  if((err = inflate(&d_stream, Z_NO_FLUSH)) == Z_STREAM_END) break;  if(err != Z_OK) {   if(err == Z_DATA_ERROR) {    d_stream.next_in = (Bytef*) dummy_head;    d_stream.avail_in = sizeof(dummy_head);    if((err = inflate(&d_stream, Z_NO_FLUSH)) != Z_OK) {     return -1;    }   } else return -1;  } } if(inflateEnd(&d_stream) != Z_OK) return -1; *ndata = d_stream.total_out; return 0;}

     如果在调试时出现了“test dword ptr [eax],eax ; probe page. 分页错误”,那就有可能是因为接收网络缓存的空间过大了。vs默认的堆栈最大值为1MB.不过可以用下边的方法进行修改:

    项目->属性->链接器->系统->堆栈保留大小

    注:这里填的是字节数
    如果你想把他扩大为2M的话,
    1024*1024*2 = 2097152

  • 相关阅读:
    翻转数组
    股神
    刮刮卡兑换
    军训队列
    击鼓传花
    上台阶
    @Service空指针异常 -JUNIT测试
    insert 配置信息
    url地址重叠
    shop = mapper.readValue(shopStr, Shop.class); shop=null的问题
  • 原文地址:https://www.cnblogs.com/zhangfeitao/p/6707345.html
Copyright © 2011-2022 走看看