CnFilePacker.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  1. {******************************************************************************}
  2. { CnPack For Delphi/C++Builder }
  3. { 中国人自己的开放源码第三方开发包 }
  4. { (C)Copyright 2001-2018 CnPack 开发组 }
  5. { ------------------------------------ }
  6. { }
  7. { 本开发包是开源的自由软件,您可以遵照 CnPack 的发布协议来修 }
  8. { 改和重新发布这一程序。 }
  9. { }
  10. { 发布这一开发包的目的是希望它有用,但没有任何担保。甚至没有 }
  11. { 适合特定目的而隐含的担保。更详细的情况请参阅 CnPack 发布协议。 }
  12. { }
  13. { 您应该已经和开发包一起收到一份 CnPack 发布协议的副本。如果 }
  14. { 还没有,可访问我们的网站: }
  15. { }
  16. { 网站地址:http://www.cnpack.org }
  17. { 电子邮件:master@cnpack.org }
  18. { }
  19. {******************************************************************************}
  20. unit CnFilePacker;
  21. {* |<PRE>
  22. ================================================================================
  23. * 软件名称:开发包不可视组件库
  24. * 单元名称:文件目录打包组件实现单元
  25. * 单元作者:CnPack开发组 子旻
  26. * 备 注:
  27. * 开发平台:PWinXP + Delphi 7.0
  28. * 兼容测试:PWin9X/2000/XP + Delphi 5/6
  29. * 本 地 化:该单元中的字符串均符合本地化处理方式
  30. * 单元标识:$Id$
  31. * 修改记录:2011.09.04 V0.03
  32. * 修正一处根目录结构错误的问题。
  33. * 2009.07.08 V0.02
  34. * 修正一处指针释放问题,增加对 D2009 的支持。
  35. * 2008.06.27 V0.01
  36. * 创建单元(整理而来)
  37. ================================================================================
  38. |</PRE>}
  39. interface
  40. {$I CnPack.inc}
  41. uses
  42. Classes, SysUtils, Windows, CnConsts, CnCompConsts, CnClasses, CnCommon;
  43. const
  44. SCnIncCounts = 20;
  45. SFileNameError = 'Destination FileName is Empty.';
  46. type
  47. //文件结构
  48. //PPackHeader |PPackDir| (TDataBlock|data|,...)
  49. // 压缩模式
  50. TCompressMode = (cmNONE, cmCustom, cmZIP, cmRAR);
  51. TBytes = array of Byte;
  52. //------------------------------------------------------------------------------
  53. // 文件头
  54. //------------------------------------------------------------------------------
  55. PPackHeader = ^TPackHeader;
  56. TPackHeader = record
  57. ZipName: array[0..7] of AnsiChar; //= ('cnpacker');
  58. FileInfoCount: Cardinal;
  59. Compress: TCompressMode;
  60. FileSize: Int64;
  61. end;
  62. //------------------------------------------------------------------------------
  63. // 文件信息
  64. //------------------------------------------------------------------------------
  65. PPackFileInformation = ^TPackFileInformation;
  66. TPackFileInformation = record
  67. Name: array[0..255] of AnsiChar;
  68. DataStart: Cardinal;
  69. end;
  70. TArrayPackFileInformation = array of TPackFileInformation;
  71. //------------------------------------------------------------------------------
  72. // 数据头
  73. //------------------------------------------------------------------------------
  74. TDataBlock = record
  75. FileName: array[0..255] of AnsiChar;
  76. //MD5:TMD5Digest;
  77. DataLength: Cardinal;
  78. end;
  79. //------------------------------------------------------------------------------
  80. // 文件描述元
  81. //------------------------------------------------------------------------------
  82. TFileCell = record
  83. ReadFileName: string;
  84. ConvertFileName: string;
  85. end;
  86. TFileCells = array of TFileCell;
  87. // 压缩接口
  88. ICnCompress = interface
  89. ['{F2379CD7-824B-4D8A-89C3-D897BF95F34C}']
  90. function GetCompressMode: TCompressMode;
  91. procedure DoCompressData(var AStream: TBytes; var ALength: Cardinal);
  92. procedure DoDeCompressData(var AStream: TBytes; var ALength: Cardinal);
  93. end;
  94. { TCnFilePacker }
  95. ECnFilePackerException = class(Exception)
  96. end;
  97. TCnFilePacker = class(TCnComponent)
  98. private
  99. {*文件头}
  100. FPackHeaderInfo: PPackHeader;
  101. {*打包文件的文件信息}
  102. FPackFileInformations: TArrayPackFileInformation;
  103. {*供外部使用的文件信息}
  104. FImportPackFileInfo: TArrayPackFileInformation;
  105. {*供外部使用的文件目录信息}
  106. FImprotPackDirectoryInfo: TArrayPackFileInformation;
  107. {*标志是否创建了保存主目录,即解包文件的目录}
  108. FCreateSavePath: Boolean;
  109. {*压缩模式}
  110. FCompressMode: TCompressMode;
  111. {*是否压缩}
  112. FCompress: Boolean;
  113. {*是否包含子目录}
  114. FPackedSubDirectory: Boolean;
  115. {*形成文件列表}
  116. FFiles: TFileCells;
  117. {*文件信息的当前数量,总数量}
  118. FCurrent, FCount: Cardinal;
  119. {*文件信息的数量,打包时=fcurrent,解包时从包中得到的}
  120. FFileinfoCount: Cardinal;
  121. {*fDestFilename是打包后的文件的文件路径}
  122. {*FSavePath是解包后存放的目录}
  123. FDestFileName, FSavePath: string;
  124. {*标志是否使用addfile函数增加了文件}
  125. FAddFilesCount: integer;
  126. {*传入的自定义压缩类}
  127. FCompressInterface: ICnCompress;
  128. {* 属性字段用到的函数,前边加prop区别}
  129. function GetPropGetPackFileDirectoryInfo: TArrayPackFileInformation;
  130. function GetPropGetPackFileInformation: TArrayPackFileInformation;
  131. function GetPropGetPackHeader: TPackHeader;
  132. {*压缩数据函数}
  133. procedure CompressData(var AStream: TBytes; var ALength: Cardinal);
  134. {*解压缩数据函数}
  135. procedure DeCompressData(var AStream: TBytes; var ALength: Cardinal);
  136. protected
  137. FPack, FDestFile: TFileStream;
  138. procedure CheckFileCellsCounts;
  139. {*如果需要压缩,不适用压缩接口的话,重载这两个虚函数!}
  140. procedure DoCompressData(var AStream: TBytes; var ALength: Cardinal); virtual;
  141. procedure DoDeCompressData(var AStream: TBytes; var ALength: Cardinal); virtual;
  142. {*得到打包文件的文件头}
  143. function GetPackHeader: PPackHeader;
  144. {*分配一块内存并得到打包文件文件的信息,由外部负责释放}
  145. function GetPackFileInformation: TArrayPackFileInformation;
  146. procedure GetComponentInfo(var AName, Author, Email, Comment: string); override;
  147. public
  148. constructor Create(AOwner: TComponent); override;
  149. destructor Destroy; override;
  150. {*形成打包文件的主函数}
  151. procedure DoPack();
  152. {*存储一个文件}
  153. procedure SaveToFile(APackFileInfo: TPackFileInformation);
  154. {*存储所以文件}
  155. procedure SaveToFiles;
  156. {*创建文件目录}
  157. procedure CreateDirectory;
  158. {*添加目录}
  159. procedure AddDircetory(ADirName: string); overload;
  160. procedure AddDircetory(ARootName, ADirName: string); overload;
  161. {*添加文件}
  162. procedure AddFile(ADirName, AFileName: string); overload;
  163. procedure AddFile(AFileName: string); overload;
  164. {*添加压缩类}
  165. procedure AddCompressClass(ACompressClass: TInterfacedClass);
  166. {*得到文件信息}
  167. property PackFileInformation: TArrayPackFileInformation read GetPropGetPackFileInformation;
  168. property PackFileDirectoryInfo: TArrayPackFileInformation read GetPropGetPackFileDirectoryInfo;
  169. published
  170. property DestFileName: string read FDestFileName write FDestFileName;
  171. property SavePath: string read FSavePath write FSavePath;
  172. property PackedSubDirectory: Boolean read FPackedSubDirectory write FPackedSubDirectory;
  173. property Compress: Boolean read FCompress write FCompress;
  174. property CompressMode: TCompressMode read FCompressMode write FCompressMode;
  175. {*得到文件头信息}
  176. property PackHeaderInformation: TPackHeader read GetPropGetPackHeader;
  177. end;
  178. implementation
  179. //以最后一个'\' 为界得到后面部分
  180. function GetFileName(AFileName: string): string;
  181. var
  182. Len, i: Cardinal;
  183. begin
  184. Len := Length(AFileName);
  185. for I := Len - 1 downto 1 do
  186. if AFileName[i] = '\' then
  187. Break;
  188. Result := Copy(AFileName, i + 1, Len - i);
  189. end;
  190. procedure Check(var ADirName: string);
  191. begin
  192. if ADirName[Length(ADirName)] <> '\' then
  193. ADirName := ADirName + '\';
  194. end;
  195. { TCnFilePacker }
  196. procedure TCnFilePacker.AddCompressClass(ACompressClass: TInterfacedClass);
  197. begin
  198. FCompressInterface := ACompressClass.Create as ICnCompress;
  199. end;
  200. procedure TCnFilePacker.AddDircetory(ARootName, ADirName: string);
  201. var
  202. CurrentDirectory, LastNameofCurrentDirectory: string;
  203. //递归目录,形成文件列表
  204. procedure FindFile(ADirName: string);
  205. var
  206. SRec: TSearchRec;
  207. tmpCurrentDirectory, tmpLastNameofCurrentDirectory: string; //保存当前目录层递归没有退栈,nnd
  208. begin
  209. if FindFirst(ADirName, faAnyFile, SRec) = 0 then
  210. begin
  211. repeat
  212. CheckFileCellsCounts;
  213. if (SRec.Name = '.') or (SRec.Name = '..') then
  214. Continue;
  215. if (SRec.Attr and faDirectory) <> 0 then
  216. begin
  217. FFiles[FCurrent].ReadFileName := CurrentDirectory + SRec.Name + '\' + IntToStr(SRec.Attr) + '?';
  218. FFiles[FCurrent].ConvertFileName := ARootName + LastNameofCurrentDirectory + SRec.Name + '\' + IntToStr(SRec.Attr) + '?';
  219. Inc(FCurrent);
  220. if FPackedSubDirectory then
  221. begin
  222. tmpLastNameofCurrentDirectory := LastNameofCurrentDirectory;
  223. tmpCurrentDirectory := CurrentDirectory;
  224. LastNameofCurrentDirectory := LastNameofCurrentDirectory + SRec.Name + '\';
  225. CurrentDirectory := CurrentDirectory + SRec.Name + '\';
  226. FindFile(copy(ADirName, 1, Length(ADirName) - 3) + SRec.Name + '\*.*');
  227. LastNameofCurrentDirectory := tmpLastNameofCurrentDirectory;
  228. CurrentDirectory := tmpCurrentDirectory;
  229. Continue;
  230. end;
  231. end;
  232. FFiles[FCurrent].ReadFileName := CurrentDirectory + SRec.Name;
  233. FFiles[FCurrent].ConvertFileName := ARootName + LastNameofCurrentDirectory + SRec.Name;
  234. Inc(FCurrent);
  235. until FindNext(SRec) <> 0;
  236. SysUtils.FindClose(SRec);
  237. end;
  238. end;
  239. begin
  240. CheckFileCellsCounts;
  241. Check(ADirName);
  242. if ARootName = ' ' then
  243. ARootName := ''
  244. else
  245. Check(ARootName);
  246. CurrentDirectory := ADirName;
  247. LastNameofCurrentDirectory := _CnExtractFileName(CurrentDirectory);
  248. if Length(ADirName) = 3 then //is 'xyz:\'
  249. LastNameofCurrentDirectory := '';
  250. FFiles[FCurrent].ReadFileName := ADirName + IntToStr(GetFileAttributes(PChar(ADirName))) + '?';
  251. FFiles[FCurrent].ConvertFileName := ARootName + IntToStr(GetFileAttributes(PChar(ADirName))) + '?';
  252. Inc(FCurrent);
  253. ADirName := ADirName + '*.*';
  254. FindFile(ADirName);
  255. end;
  256. procedure TCnFilePacker.AddDircetory(ADirName: string);
  257. begin
  258. AddDircetory(' ', ADirName);
  259. end;
  260. procedure TCnFilePacker.AddFile(AFileName: string);
  261. begin
  262. CheckFileCellsCounts;
  263. FFiles[FCurrent].ReadFileName := '?';
  264. FFiles[FCurrent].ConvertFileName := '16' + '?';
  265. Inc(FCurrent);
  266. FFiles[FCurrent].ReadFileName := AFileName;
  267. FFiles[FCurrent].ConvertFileName := _CnExtractFilename(AFileName);
  268. Inc(FCurrent);
  269. end;
  270. procedure TCnFilePacker.AddFile(ADirName, AFileName: string);
  271. begin
  272. CheckFileCellsCounts;
  273. check(ADirName);
  274. FFiles[FCurrent].ReadFileName := ADirName + '?';
  275. FFiles[FCurrent].ConvertFileName := ADirName + '16' + '?';
  276. Inc(FCurrent);
  277. FFiles[FCurrent].ReadFileName := AFileName;
  278. FFiles[FCurrent].ConvertFileName := ADirName + _CnExtractFilename(AFileName);
  279. Inc(FCurrent);
  280. end;
  281. procedure TCnFilePacker.CheckFileCellsCounts;
  282. begin
  283. if FCurrent >= FCount then
  284. begin
  285. FCount := FCount + SCnIncCounts;
  286. SetLength(FFiles, FCount);
  287. end;
  288. end;
  289. procedure TCnFilePacker.CompressData(var AStream: TBytes; var ALength: Cardinal);
  290. begin
  291. if FCompressInterface = nil then
  292. DoCompressData(AStream, ALength)
  293. else if CompressMode = FCompressInterface.GetCompressMode then
  294. FCompressInterface.DoCompressData(AStream, ALength);
  295. end;
  296. constructor TCnFilePacker.Create(AOwner: TComponent);
  297. begin
  298. inherited Create(AOwner);
  299. //fms := TMemoryStream.Create;
  300. FCompress := False;
  301. FPackedSubDirectory := true;
  302. FAddFilesCount := -1;
  303. FCurrent := 0;
  304. FCount := 20;
  305. SetLength(FFiles, FCount);
  306. FCreateSavePath := False;
  307. end;
  308. procedure TCnFilePacker.CreateDirectory;
  309. var
  310. i: Integer;
  311. S, DirName: string;
  312. attr: Byte;
  313. begin
  314. if not FCreateSavePath then
  315. begin
  316. ForceDirectories(SavePath);
  317. FCreateSavePath := True;
  318. end;
  319. for I := 0 to FFileinfoCount - 1 do
  320. begin
  321. S := {$IFDEF UNICODE}String{$ENDIF}(FPackFileInformations[i].Name);
  322. if Length(s) < 7 then
  323. Continue; //xyz:\16?
  324. if s[Length(s)] = '?' then
  325. begin
  326. attr := StrToInt(Copy(s, Length(s) - 2, 2));
  327. s := Copy(s, 1, Length(s) - 3);
  328. DirName := SavePath + '\' + s;
  329. ForceDirectories(DirName);
  330. SetFileAttributes(PChar(dirname), attr);
  331. end
  332. end;
  333. end;
  334. procedure TCnFilePacker.DeCompressData(var AStream: TBytes; var ALength: Cardinal);
  335. begin
  336. if FCompressInterface = nil then
  337. DoDeCompressData(AStream, ALength)
  338. else if CompressMode = FCompressInterface.GetCompressMode then
  339. FCompressInterface.DoDeCompressData(AStream, ALength);
  340. end;
  341. destructor TCnFilePacker.Destroy;
  342. begin
  343. if FPackHeaderInfo <> nil then
  344. begin
  345. FreeMem(FPackHeaderInfo);
  346. FPackHeaderInfo := nil;
  347. end;
  348. inherited;
  349. end;
  350. procedure TCnFilePacker.DoCompressData(var AStream: TBytes; var ALength: Cardinal);
  351. begin
  352. end;
  353. procedure TCnFilePacker.DoDeCompressData(var AStream: TBytes; var ALength: Cardinal);
  354. begin
  355. end;
  356. procedure TCnFilePacker.SaveToFile(APackFileInfo: TPackFileInformation);
  357. var
  358. f: TFileStream; //临时文件流,保存文件
  359. db: TDataBlock;
  360. Tdb: TBytes; //临时缓冲区,存中间数据
  361. S: string;
  362. begin
  363. S := {$IFDEF UNICODE}String{$ENDIF}(APackFileInfo.Name);
  364. if (s = '') or (s[Length(s)] = '?') then
  365. Exit;
  366. try
  367. FDestFile := TFileStream.Create(DestFileName, fmOpenReadWrite);
  368. if fSavePath[length(fSavePath)] = '\' then
  369. SetLength(fSavePath, Length(fSavePath) - 1);
  370. FDestFile.Position := APackFileInfo.DataStart;
  371. FDestFile.Read(db, SizeOf(db));
  372. if db.DataLength <> 0 then
  373. begin
  374. SetLength(Tdb, db.DataLength);
  375. FDestFile.Read(Tdb[0], db.DataLength);
  376. f := TFileStream.Create(SavePath + '\' + S, fmCreate or fmOpenReadWrite);
  377. if CompressMode <> cmNONE then
  378. DeCompressData(Tdb, db.DataLength);
  379. f.Write(tdb[0], db.DataLength);
  380. f.Free;
  381. end
  382. else
  383. begin
  384. f := TFileStream.Create(SavePath + '\' + S, fmCreate or fmOpenReadWrite);
  385. f.Free;
  386. end;
  387. finally
  388. FreeAndNil(FDestFile);
  389. end;
  390. end;
  391. function TCnFilePacker.GetPackFileInformation: TArrayPackFileInformation;
  392. var
  393. i: Integer;
  394. db: TDataBlock;
  395. fms: TFileStream; //临时文件流
  396. begin
  397. if FPackHeaderInfo <> nil then
  398. begin
  399. FreeMem(FPackHeaderInfo);
  400. FPackHeaderInfo := nil;
  401. end;
  402. FPackHeaderInfo := GetPackHeader;
  403. CompressMode := FPackHeaderInfo^.Compress;
  404. if FPackHeaderInfo^.ZipName <> 'CNPACKER' then//文件头不是cnpacker,退出
  405. Exit;
  406. Fms := TFileStream.Create(DestFileName, fmOpenRead);
  407. Fms.Position := SizeOf(TpackHeader);
  408. SetLength(Result, FPackHeaderInfo^.FileInfoCount);
  409. FFileinfoCount := FPackHeaderInfo^.FileInfoCount;
  410. for I := 0 to FPackHeaderInfo^.FileInfoCount - 1 do
  411. begin
  412. Fms.Read(db, SizeOf(db));
  413. StrCopy(Result[i].Name, db.FileName);
  414. Result[i].DataStart := Fms.Position - SizeOf(db);
  415. Fms.Position := Fms.Position + LongInt(db.DataLength);
  416. end;
  417. Fms.Free;
  418. end;
  419. function TCnFilePacker.GetPackHeader: PPackHeader;
  420. var
  421. fms: TFileStream;
  422. begin
  423. GetMem(Result, SizeOf(TPackHeader));
  424. Fms := TFileStream.Create(DestFileName, fmOpenRead);
  425. Fms.Position := 0;
  426. Fms.Read(Result^, SizeOf(TPackHeader));
  427. FreeAndNil(fms);
  428. end;
  429. procedure TCnFilePacker.GetComponentInfo(var AName, Author, Email,
  430. Comment: string);
  431. begin
  432. AName := SCnFilePackerName;
  433. Author := SCnPack_ZiMin;
  434. Email := SCnPack_ZiMinEmail;
  435. Comment := SCnFilePackerComment;
  436. end;
  437. function TCnFilePacker.GetPropGetPackFileDirectoryInfo: TArrayPackFileInformation;
  438. var
  439. i: Cardinal;
  440. S: string;
  441. count, current: Cardinal;
  442. begin
  443. count := SCnIncCounts;
  444. current := 0;
  445. SetLength(FImprotPackDirectoryInfo, count);
  446. FPackFileInformations := GetPackFileInformation;
  447. for I := 0 to FFileinfoCount - 1 do
  448. begin
  449. S := {$IFDEF UNICODE}String{$ENDIF}(FPackFileInformations[i].Name);
  450. if S[Length(s)] = '?' then
  451. begin
  452. S := IncludeTrailingBackslash(_CnExtractFilePath(S));
  453. if current = count then
  454. begin
  455. count := count + SCnIncCounts;
  456. SetLength(FImprotPackDirectoryInfo, count);
  457. end;
  458. StrPCopy(FImprotPackDirectoryInfo[current].Name, {$IFDEF UNICODE}AnsiString{$ENDIF}(S));
  459. FImprotPackDirectoryInfo[current].DataStart := FPackFileInformations[i].DataStart;
  460. Inc(current);
  461. end;
  462. end;
  463. SetLength(FImprotPackDirectoryInfo, current);
  464. Result := FImprotPackDirectoryInfo;
  465. end;
  466. function TCnFilePacker.GetPropGetPackFileInformation: TArrayPackFileInformation;
  467. var
  468. i: Cardinal;
  469. S: string;
  470. count, current: Cardinal;
  471. begin
  472. count := SCnIncCounts;
  473. current := 0;
  474. SetLength(FImportPackFileInfo, count);
  475. FPackFileInformations := GetPackFileInformation;
  476. for I := 0 to FFileinfoCount - 1 do
  477. begin
  478. S := {$IFDEF UNICODE}String{$ENDIF}(FPackFileInformations[i].Name);
  479. if S[Length(s)] <> '?' then
  480. begin
  481. if current = count then
  482. begin
  483. count := count + SCnIncCounts;
  484. SetLength(FImportPackFileInfo, count);
  485. end;
  486. FImportPackFileInfo[current].Name := FPackFileInformations[i].Name;
  487. FImportPackFileInfo[current].DataStart := FPackFileInformations[i].DataStart;
  488. Inc(current);
  489. end;
  490. end;
  491. SetLength(FImportPackFileInfo, current);
  492. Result := FImportPackFileInfo;
  493. end;
  494. function TCnFilePacker.GetPropGetPackHeader: TPackHeader;
  495. begin
  496. if FPackHeaderInfo <> nil then
  497. begin
  498. FreeMem(FPackHeaderInfo);
  499. FPackHeaderInfo := nil;
  500. end;
  501. FPackHeaderInfo := GetPackHeader;
  502. Result := FPackHeaderInfo^;
  503. end;
  504. procedure TCnFilePacker.DoPack();
  505. var
  506. ph: TPackHeader;
  507. db: TDataBlock;
  508. i: Integer;
  509. Tdb: TBytes;
  510. f: TFileStream;
  511. begin
  512. FillChar(ph, SizeOf(Tpackheader), #0);
  513. if DestFileName = '' then
  514. ECnFilePackerException.Create(SFileNameError);
  515. if not FileExists(DestFileName) then
  516. begin
  517. FPack := TFileStream.Create(DestFileName, fmCreate);
  518. FPack.Position := 0;
  519. //步过文件头
  520. FPack.Seek(SizeOf(TPackHeader), soFromCurrent);
  521. end
  522. else
  523. begin
  524. FPack := TFileStream.Create(DestFileName, fmOpenReadWrite);
  525. FPack.Read(ph, SizeOf(ph));
  526. FPack.Position := FPack.Size;
  527. end;
  528. //循环all文件
  529. for I := 0 to FCurrent - 1 do
  530. begin
  531. if FFiles[i].ReadFileName[Length(FFiles[i].ReadFileName)] = '?' then
  532. begin
  533. strpcopy(db.FileName, {$IFDEF UNICODE}AnsiString{$ENDIF}(Ffiles[i].ConvertFileName));
  534. db.DataLength := 0;
  535. FPack.Write(db, SizeOf(db));
  536. end
  537. else
  538. begin
  539. f := TFileStream.Create(FFiles[i].ReadFileName, fmOpenRead);
  540. strpcopy(db.FileName, {$IFDEF UNICODE}AnsiString{$ENDIF}(Ffiles[i].ConvertFileName));
  541. db.DataLength := F.Size;
  542. if db.DataLength <> 0 then
  543. begin
  544. SetLength(Tdb, db.DataLength);
  545. f.Read(Tdb[0], db.DataLength);
  546. if CompressMode <> cmNONE then
  547. CompressData(tdb, db.DataLength);
  548. FPack.Write(db, SizeOf(db));
  549. FPack.Write(tdb[0], db.DataLength);
  550. FreeAndNil(f);
  551. end
  552. else
  553. begin
  554. FPack.Write(db, SizeOf(db));
  555. FreeAndNil(f);
  556. end;
  557. end;
  558. end;
  559. //写文件头
  560. ph.ZipName := 'CNPACKER';
  561. ph.Compress := CompressMode;
  562. ph.FileSize := FPack.Size;
  563. Inc(ph.FileInfoCount, FCurrent);
  564. FPack.Position := 0;
  565. FPack.Write(ph, SizeOf(ph));
  566. FreeAndNil(FPack);
  567. FCurrent := 0;
  568. FCount := 20;
  569. SetLength(Ffiles, FCount);
  570. end;
  571. procedure TCnFilePacker.SaveToFiles;
  572. var
  573. i: integer;
  574. begin
  575. if FPackFileInformations = nil then
  576. FPackFileInformations := self.GetPackFileInformation; //先得到目录,
  577. Self.CreateDirectory; //创建目录
  578. for I := 0 to Length(FPackFileInformations) - 1 do
  579. begin
  580. Self.SaveToFile(FPackFileInformations[i]); //枚举调用解包每个文件
  581. end;
  582. FreeAndNil(FDestFile);
  583. end;
  584. end.