三层中关于保持二进制文件流被丢失一部分的问题!(文本文件流保存就成功,晕啊!!!)(200)

  • 主题发起人 主题发起人 oiget
  • 开始时间 开始时间
O

oiget

Unregistered / Unconfirmed
GUEST, unregistred user!
三层中(Midas控件),要把一个.exe文件保存到Oracle表的Blob字段中,以下代码应该没什么问题的了,测试通过,而且保存文本文件的流都成功!但保存exe等文件,无论文件大小,保存到数据库后字节数都要比源文件小!!难道真的是ClientDataSet[MIDAS]的Bug么,可以解决的么?非常感谢!!!【开发版本Delphi7】代码:
代码:
  procedure   TF_UpGrade.UpLoadPro(FileName: string);  const      BufSize   =   $F000;  var      Counter,   N:   Integer;      Buffer:   PAnsiChar;      FieldStrm:   TStream;      ExeFileStream:TFileStream;      size_tmp:   Double;      Fname,gv:   string;  begin        if Filename='' then Fname:=extractFileName(application.ExeName)        else Fname:=FileName;        gv:=GetVersion(Fname,true);//取得exe文件的版本号        //with   qry   do            begin              qry.Open; //qry为clientdataset              qry.Edit;              try                  ExeFileStream:=TFileStream.Create(Fname,fmopenRead);     //打开文件                  FieldStrm   :=   qry.CreateBlobStream(qry.FieldByName('PC'),   bmWrite);                  GetMem(Buffer,   BufSize);                  try                      Counter   :=   ExeFileStream.Size;                      size_tmp   :=   ExeFileStream.Size;                      ProgressBar1.Position   :=   0;                      ProgressBar1.Max   :=   Counter   div   BufSize;     //每次上传文件流为61440   byte   =   $F000                      while   Counter   <>   0   do                          begin                            if   Counter   >   BufSize   then                                N   :=   BufSize                            else                                N   :=   Counter;                            ExeFileStream.ReadBuffer(Buffer^,   N);                            FieldStrm.WriteBuffer(Buffer^,   N);                            Dec(Counter,   N);                            ProgressBar1.Position   :=   ProgressBar1.Position   +   1;                            Application.ProcessMessages;                        end;                  cmd.Params.Clear;                  cmd.CommandText:='update upGrade set PC=:spc,PV=:spv where Rtrim(pname) ='+quotedStr(Fname);                  cmd.Params.ParamByName('spc').LoadFromStream(FieldStrm,ftBlob); //FieldStrm(二进制流)被保存到数据库后就都变小了,晕啊!!!                  cmd.Params.ParamByName('spv').Value:=gv;                  cmd.ExecSQL;                  finally                      FreeMem(Buffer,   BufSize);                      FieldStrm.Free;                  end;                  Application.MessageBox('新版本程序上传至服务器成功!','提示',MB_OK+MB_IconInformation);              finally                  ProgressBar1.Position   :=   ProgressBar1.Max;                  ExeFileStream.Free;              end;          end;  end;
 
你把文件用某种算法编码一下,编码后成为一个字符串,然后存入数据库,读取时再把字符串解码还原试试
 
我有个想法就是,把exe文件转为16进制的文本文件,然后保存至数据库!取数据后再把16进制的文本文件还原为exe文件,这样是否可行的呢,有转换的函数的么?!
 
多谢szhcracker给了启示!实践表明是文本格式的话都能保持成功的!现在的关键就是 exe <--> txt 之间如何互相转换呢 ?!
 
你不必把exe搞成txt,只要把exe编码成一个string后再处理,给你一段代码参考:uses ZLib, Classes, EncdDecd, SysUtils; function CompressString(const Source: string; CompressionLevel: TCompressionLevel = clMax): string;var CompressionStream: TCompressionStream; MemorySteam: TMemoryStream; StringStream: TStringStream;begin MemorySteam := TMemoryStream.Create(); try CompressionStream := TCompressionStream.Create(CompressionLevel, MemorySteam); try CompressionStream.Write(Source[1], Length(Source)); finally CompressionStream.Free; end; StringStream := TStringStream.Create(''); try MemorySteam.SaveToStream(StringStream); Result := StringStream.DataString; finally StringStream.Free; end; finally MemorySteam.Free; end;end;function UnCompressString(const Source: string): string;var DeCompressionStream: TDeCompressionStream; MemorySteam: TMemoryStream; DataStream: TMemoryStream; Buf: TByteArray; ReadBufLen: Integer;begin MemorySteam := TMemoryStream.Create(); DataStream := TMemoryStream.Create(); try MemorySteam.Size := Length(Source); Move(Source[1], MemorySteam.Memory^, MemorySteam.Size); DeCompressionStream := TDeCompressionStream.Create(MemorySteam); try ReadBufLen := DeCompressionStream.Read(Buf, SizeOf(Buf)); while ReadBufLen > 0 do begin DataStream.Write(Buf, ReadBufLen); ReadBufLen := DeCompressionStream.Read(Buf, SizeOf(Buf)); end; SetLength(Result, DataStream.Size); Move(DataStream.Memory^, Result[1], DataStream.Size); finally DeCompressionStream.Free; end; finally MemorySteam.Free; DataStream.Free; end;end;function EncodeFile(const AFileName: string; var AEncodedString, AFileType: String): Boolean; //AFileName 文件名称 //AEncodedString文件编码后的String //AFileType文件类型,后缀var MemoryStream: TMemoryStream; StringStream: TStringStream; P: Integer; TS: TStrings; I: Integer;begin Result := False; if not FileExists(AFileName) then Exit; MemoryStream := TMemoryStream.Create; StringStream := TStringStream.Create(''); TS := TStringList.Create; try MemoryStream.LoadFromFile(AFileName); AFileType := ExtractFileName(AFileName); P := POS('.', AFileType); AFileType := Copy(AFileType, P + 1, Length(AFileType)); MemoryStream.Position := 0; EncodeStream(MemoryStream, StringStream); AEncodedString := EncodeString(CompressString(StringStream.DataString)) ; TS.Text := AEncodedString; AEncodedString := ''; for I := 0 to TS.Count - 1 do AEncodedString := AEncodedString + TS;//去掉换行符 finally MemoryStream.Free ; StringStream.Free ; TS.Free ; end; Result := True;end;procedure SaveToDB;var EXEVALUE: string;begin EncodeFile('C:/test.exe', EXEVALUE, 'exe'); // 编码 // 存入数据库示例 with FSQLQuery do // FSQLQuery 为 TSQLQuery 类 begin Close; SQL.Clear; SQL.Add(SQLStr); Params.Clear; Params.Add; Params.Items[0].DataType := ftBlob; MemoryStream := TMemoryStream.Create ; StringStream := TStringStream.Create(UnCompressString(DecodeString(EXEVALUE))); try DecodeStream(StringStream,MemoryStream); Params.Items[0].LoadFromStream(MemoryStream, ftBlob); finally MemoryStream.Free; StringStream.Free; end; try ExecSQL(False); except ...; end; Close; end;end;你试试,祝你好运。
 
主要看看 SaveToDB 过程
 
非常感恩 szhcracker !回去好好研究下您的代码!
 
szhcracker兄 的代码很好!EncodeString,DecodeString可以用于加密解密对吧?可惜现在我的电脑没有调试的环境,对了,从Blob取得的字符串如何还原为文件(SaveToFile)好呢?szhcracker兄,可以给个示例么,等回去我就调试,我主要是想弄一个自动升级的代码,就是把exe文件存在数据库库,客户端启动的时候检测版本,如果版本不一致,就从数据库下载exe覆盖旧的。二层的没问题,现在三层的就要转换转换 ?
 
我的EncodeString,DecodeString过程只是简单的编码、解码,稍微改改就可以用于加密解密了,其实整体思路就是编码后生成字符串,然后压缩写入数据库,压缩是为了提高效率(特别是在三层架构中),至于读取也是一样,先按照字符串形式读出,然后解压、解码后再写成文件即可,你试试吧。建议你在数据库中同时存入完整的文件名(扩展名一定要,至于路径就随便了),这样读取后就按照保存时的文件名生成就可以了。我可以明确的告诉你:.pdf、.jpg、.bmp、.doc文件是肯定没有问题的(其是我给的代码就是我的系统中用的),至于exe到没有试过。另外:如果程序不是很大(可以通过UPX等压缩)而且环境允许,你还可以考虑用Ftp、Http等方式进行更新,这样简单些,而且速度也不错,至于判断是否要进行更新,可以通过exe文件的修改时间来处理,我有一个系统就是这么处理的,很稳定。
 
非常感谢szhcracker!!我第一次写三层,用Midas的改进版,是通过TCP方式连接到中间层服务器,看来以后的程序的发布可以不用管什么数据库的客户端了,三层的这个真是好!最关键的地方是三层的应用基本是基于互联网的,所以数据传输的压缩和加密就显得特别重要了,我有个不知道是否切实际的想法就是:如果以后我把Midas数据传输进行修改一下,把数据传输的过程进行严格的压缩和加密,这样一来是否就可以扔掉VPN了呢?当然我自知我的水平太次,这只是一个想法!
 
szhcracker兄:我调试了下代码,好像是可以保存进去数据库了,但字节数比源文件要大,我想应该是我弄错了,怎么好像压缩不起作用的?您的思路是肯定对的,也许是编码,解密,压缩,解压把俺弄糊涂了,比如: StringStream := TStringStream.Create(UnCompressString(DecodeString(EXEVALUE)));和DecodeStream(StringStream,MemoryStream);我想不明白了,EXEVALUE已经是压缩了并已经编码了字符串对吧?为什么又要进行解码和解压呢,然后的流要Decode呢?szhcracker兄,我还没消化好您的程序,小弟愚昧,可否指点迷津呢,再次感激不尽!
 
后退
顶部