有谁用c++builder编写过gzip流式文件的解压?

xugeng 2007-10-15 04:43:09
我已搞了半天控件总是不正确
所以请说明用什么控件及示例(由要求流文件in,由流文件出),谢谢了
...全文
953 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
Waiting4you 2007-11-30
  • 打赏
  • 举报
回复
把zlib.lib加入工程: 菜单Project\Add to Project..., 在弹出打开对话框中文件类型选Library file(*.lib),找到zlib.lib打开就可以了
hohoyeh 2007-11-29
  • 打赏
  • 举报
回复
请帮忙看看是什么原因。


我的操作步骤是这样的,
先从网上下载了1.23的ZLIB的源码,
我用的是BCB 6,执行
make -f win32/Makefile.bor会生成zlib.lib.
成功,没有任何错误。

我将zlib.lib复制到BCB 6安装目录LIBS中,将相关的.h文档放入Include中,
代码完全按照原来的写法:

//---------------------------------------------------------------------------

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include < Forms.hpp>
#include <zlib.h>
#include <io.h>
#include <fcntl.h>
#include <sys\stat.h>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
TMemo *Memo1;
TButton *Button1;
void __fastcall Button1Click(TObject *Sender);
private: // User declarations
public: // User declarations
__fastcall TForm1(TComponent* Owner);
bool __fastcall TStreamUncompress(TStream *StmDesc, TStream *StmGzip);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif











//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#include <zlib.h>
#include <io.h>
#include <fcntl.h>
#include <sys\stat.h>
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
TFileStream *mstrSrc = new TFileStream("c:\\Plan.txt.gz",fmOpenRead);

TFileStream *mstrDesc = new TFileStream("c:\\desc.txt",fmCreate);

TStreamUncompress(mstrDesc,mstrSrc);

Memo1->Lines->LoadFromStream(mstrDesc);
delete mstrSrc;
delete mstrDesc;

}
//---------------------------------------------------------------------------

bool __fastcall TForm1::TStreamUncompress(TStream *StmDesc, TStream *StmGzip)
{
char buf[512];
int r=0;
// 建立管道
int fdpipe[2]; //fdpipe[1]是用于写入的管道, fdpipe[0]是用于读的管道
if( _pipe( fdpipe, StmGzip->Size, O_BINARY ) == -1 ) return false;

// 写StmGzip到管道fdpipe[1]
StmGzip->Seek(0,0);
while( ( r = StmGzip->Read(buf,sizeof(buf))) >0 ) _write( fdpipe[1], buf, r);
close(fdpipe[1]);

// 用zlib读管道并解压到stmDesc中
gzFile gSrc = gzdopen(dup(fdpipe[0]),"rb"); //以读方式打开中...
if(gSrc == NULL)
{
close(fdpipe[0]);
return false;
}

while(( r = gzread(gSrc,buf,sizeof(buf)) ) > 0 )
{
StmDesc->Write(buf,r); // 解压中...
}

gzclose(gSrc);
close(fdpipe[0]);
return true;
}





然后开始编译,结果出现错误:

见附件 bcb.bmp



于是我尝试更改zcon.h,文件相应错误如下:

typedef Byte FAR Bytef;

改成

typedef System::Byte FAR Bytef;



结果出现如下错误:

[Linker Error] Unresolved external '_gzdopen' referenced from D:\PROJECTS\BCB\ZLIBTEST\UNIT1.OBJ
[Linker Error] Unresolved external '_gzread' referenced from D:\PROJECTS\BCB\ZLIBTEST\UNIT1.OBJ
[Linker Error] Unresolved external '_gzclose' referenced from D:\PROJECTS\BCB\ZLIBTEST\UNIT1.OBJ



百思不得其解,特求助。。
xugeng 2007-10-22
  • 打赏
  • 举报
回复
测试成功,非常感谢!!!!
请留个email我们好联系,谢了
(我的:xugeng@sohu.com)
xugeng 2007-10-22
  • 打赏
  • 举报
回复
我试试看,谢了
Waiting4you 2007-10-20
  • 打赏
  • 举报
回复
应该是先把gzip文件从内存写到硬盘, 然后再用gzopen读到内存就行了, 只是一次写入而已. 就当临时文件吧,呵呵.

如果楼主愿意,可以看一下zlib库里的gzio.c里的源代码, 它里面就是gzopen,gzread,gzwrite等的代码, 也许可以参考一下改出内存到内存的解压方式.

附, 从文件file1.gz解压并读取到TMemoryStream里的代码

gzFile gSrc = gzopen("file1.gz","rb"); //以读方式打开file1.gz
int r=0;
char buf[512];

TMemoryStream * stmDesc = new TMemoryStream; // 目标是TMemoryStream

while(( r = gzread(gSrc,buf,512) ) > 0 )
{
stmDesc->Write(buf,r); // 用gzread读出来的就是解压后的数据, 长度是r
}

gclose(gSrc);

// 数据已经在stmDesc里了
stmDesc->Seek(0,soFromBeginning);
Waiting4you 2007-10-20
  • 打赏
  • 举报
回复
研究了两个多小时,终于研究出怎么把内存流里的gz文件直接解压到另一个内存流里了(利用pipe),下面是源代码:

函数StreamUncompress
参数1: TMemoryStream *StmDesc -- 目标内存流,用于存放解压后的数据
参数2: TMemoryStream *StmGzip -- 源内存流,存放gz压缩数据的内存流

void StreamUncompress(TMemoryStream *StmDesc, TMemoryStream *StmGzip)
{
// 建立管道
int fdpipe[2];
if( _pipe( fdpipe, StmGzip->Size, O_BINARY ) == -1 ) return;

// 写StmGzip到管道
_write( fdpipe[1], StmGzip->Memory, StmGzip->Size );
close(fdpipe[1]); // fdpipe[1]是用于写入的管道

// 用gzFile读管道
int r=0;
char buf[512];

gzFile gSrc = gzdopen(dup(fdpipe[0]),"rb"); //以读方式打开
while(( r = gzread(gSrc,buf,512) ) > 0 )
{
StmDesc->Write(buf,r); // 用gzread读出来的就是解压后的数据, 长度是r
}
gzclose(gSrc);
close(fdpipe[0]); // 这是用于读的管道
}


另外:很简单地修改一下可以做成void StreamUncompress(TStream *StmDesc, TStream *StmGzip)这种形式,这样它的适应性就更大了,比如使用TFileStream直接解压gz文件,使用TBlobStream直接读取数据库中gz压缩的Blob数据,使用TWinSocketStream...

相应地也可以再做一个void StreamCompress(TStream *StmGzip, TStream *StmSrc),那就无敌了,哈哈...

嗯,等会儿有空放到偶的Blog上去.


使用方法:
void __fastcall TForm1::btn1Click(TObject *Sender)
{
TMemoryStream *mstrSrc = new TMemoryStream;
mstrSrc->LoadFromFile("c:\\Plan.txt.gz"); // 我自己做试验用的,为了得到一个gzip的内存流,楼主应该是从别的地方得到的内存流吧?

TMemoryStream *mstrDesc = new TMemoryStream; // 目标内存流

StreamUncompress(mstrDesc,mstrSrc); // mstrSrc -->解压--> mstrDesc

delete mstrSrc;

mstrDesc->SaveToFile("c:\\desc.txt"); // 存出来看看对不对:)
delete mstrDesc;

}
xugeng 2007-10-20
  • 打赏
  • 举报
回复
我不太清楚zlib对gz文件解压方式,我试过zlib能对它自已压缩的文件进行解压,但是对gz文件不能正确解压(我试过用文件方式),但是用gzip的却可以直接解压gzip -df xxx.gz
xugeng 2007-10-19
  • 打赏
  • 举报
回复
我下载的是一个gzip的数据流,因为我可以保存到本地.gz后,可以用winrar打开的.里面是一个完整的文件

我现在就不知道有什么好的方法来实现在流中实现解压,但是将gzip格式保存到硬盘后->解压gzip(实际上也需要作读取,写入)->再导入到内存中,在硬盘上做了两次读取/两次写入,效率很低!
Waiting4you 2007-10-18
  • 打赏
  • 举报
回复
一般所谓的TMemoryStream里的压缩数据应该是用zlib算法压缩的数据,这种数据可以直接用zlib库的uncompress解压,但最好是预先知道解压后的大小,不然确实给的空间大小确实是个难题. 但它不是真正的gzip文件格式,gzip是除了zlib的压缩数据外还有其它信息数据,比如之前所说的原数据大小之类的东东.

楼主可以先确定一下是哪一种, 你把TMemoryStream里的数据直接保存成一个文件,看看能不能用解压软件解压,如果不行就说明是zlib压缩数据,行的话就是gzip文件的内存镜像了.

对于gzip的内存镜像,最简单的方法当然是保存成临时文件再解压啦, 另外可以试试用有名管道的方法模拟成一个文件欺骗gzopen(偶没试过,不一定行)
xugeng 2007-10-17
  • 打赏
  • 举报
回复
谁有代码可以将TMemoryStream中的内容(gzip)解压结果直接转成一个新的TMemorySream,如果用文件方式转换大约要花3-5倍的时间去在文件保存和读取中,实在不合算.有没有哪个公司做该控件的?
Waiting4you 2007-10-16
  • 打赏
  • 举报
回复
你用的是BCB2006/2007? 我这里只有BCB6,没法试你的代码.

个人认为:
while(1)
pCompress- >Seek(1,soFromCurrent); //这里出现异常是正常的,因为你把当前位置不断地往前移,到文件尾它总是要有意见的吧?

如果你只是想把 gzip格式的file1.gz 解压成普通格式file2, 代码如下:
gzFile gSrc = gzopen("file1.gz","rb"); //以读方式打开file1.gz
int r=0;
char buf[512];

int hDesc = FileCreate("file2");
while(( r = gzread(gSrc,buf,512) ) > 0 )
{
FileWrite(hDesc,buf,r);
}
FileClose(hDesc);

gclose(gSrc);

反过来把file2压缩成file1.gz,代码如下:
int hSrc = FileOpen("file2",fmOpenRead);

int r=0;
char buf[512];

gzFile gDesc = gzopen("file1.gz","wb"); // 以写方式打开
while(( r = FileRead(hSrc,buf,512) ) > 0 )
{
gzwrite(gDesc,buf,r);
}
gclose(gDesc);

FileClose(hSrc);

需要zlib库,安装方法见楼上。
xuhaoran999 2007-10-16
  • 打赏
  • 举报
回复
有没有直接对流进行操作的方法?
xuhaoran999 2007-10-15
  • 打赏
  • 举报
回复
我在网上找到很多例子,但是没有一个能运行通过,都会抛出异常:如下面:

太多问题了,网上说是否为:必须知道解压后的文件大小?那怎么可能?有用吗?

void __fastcall TForm1::Button2Click(TObject *Sender) // 解压
{
TMemoryStream *pMemsrc=new TMemoryStream;
pMemsrc->LoadFromFile("E:\\Compressed.dat");
pMemsrc->Seek(0,soFromBeginning);

TDecompressionStream *pCompress;
pCompress=new TDecompressionStream(pMemsrc);
pCompress->Seek(0,soFromBeginning);
TMemoryStream *pDestMem=new TMemoryStream;
pCompress->Seek(0,soFromBeginning);
try
{
while(1)
pCompress->Seek(1,soFromCurrent); //出现异常
}
catch(...)
{
}
int count=pCompress->Position;
char * pbuf=(char*)malloc(count);
pCompress->Seek(0,soFromBeginning);
pCompress->ReadBuffer(pbuf,count);
pDestMem->WriteBuffer(pbuf,count);
pDestMem->Seek(0,soFromBeginning);
pDestMem->SaveToFile("E:\\test1.bdb");

delete pDestMem;
delete pCompress;
delete pMemsrc;
}

另一个:

void DecompressFile(AnsiString FileName, AnsiString DecompressedFileName)

{

TFileStream *FIn, *FOut;

TDecompressionStream* D;

Byte Buf[4096];

int Count;

if(!FileExists(FileName)) throw Exception("File not Exist");



FIn = new TFileStream( FileName, fmOpenRead | fmShareDenyWrite );

FOut = NULL;



if (FileExists(DecompressedFileName))

FOut = new TFileStream(DecompressedFileName, fmOpenWrite | fmShareExclusive);

else

FOut = new TFileStream(DecompressedFileName, fmCreate | fmShareExclusive);

try

{

D = new TDecompressionStream(FIn);

try

{

for(Count = 1;Count>0;)

{

Count = D->Read(Buf, sizeof(Buf)); //出现异常

FOut->Write(Buf,Count);

}

}

__finally

{

delete D;

}

}

__finally

{

delete FIn;

delete FOut;

}

}

xugeng 2007-10-15
  • 打赏
  • 举报
回复
to waiting4you:


行不?谢谢了

xugeng 2007-10-15
  • 打赏
  • 举报
回复
最好给个例子吧,我试过好多控件都不行,谢了
Waiting4you 2007-10-15
  • 打赏
  • 举报
回复
楼主可以到网上找zlib-1.2.3版本, 解压后

make -f win32/Makefile.bor会生成zlib.lib.

把zlib.lib加入工程, cpp文件里#include <zlib.h> 就可以用了
Waiting4you 2007-10-15
  • 打赏
  • 举报
回复
zlib库本来就支持流输入输出的:

gzopen
gzread
gzwrite
gzseek
gzclose
...

就象写普通文件一样。

如果在内存中的是gzip数据,可以使用uncompress解压

13,826

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder相关内容讨论区
社区管理员
  • 基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧