Наша взаимовыгодная связь https://banwar.org/
Повернувшись з відпустки зі столиці Чехії - міста Прага (якщо ви там ще не були, то обов'язково повинні там побувати), можна приступати до освоєння нового релізу Delphi XE2. Поки що я не буду торкатися такі нові технології як LiveBinding & FireMonkey, а зупинюся на більш простому - нові можливості RTL. Загалом то їх не так вже й багато , І думаю найбільш корисне нововведення - підтримка Zip-архівів.
Якщо подивитися на список удосконалень RTL, то з точки зору нового функціоналу тут тільки два класи - TZipFile & TLoginCredentialService. Тобто я маю на увазі, що лише ці класи вирішують деякі прикладні задачі, інші еже нововведення розширюють або поліпшують існуюче. TOSVersion - повертає інформацію про операційну систему (знову ж роботи ніякої не виконує), нові методи для TPoint і т.п. я думаю будуть вельми корисні. Сам недавно дивувався чому їх досі не було, коли писав мильні бульбашки . Але повернемося до роботи з zip-архівами. Згаданий функціонал розташований в модулі System.Zip. І тут можна помітити два косяка. По-перше написавши в uses System.Z в випадаючому списку буде тільки ZLib, а модуль Zip буде відсутній (дивина). Друге, що можна помітити - відкривши шуканий модуль, ви побачите що весь код відкоментований з використанням XML тегів. Але ось невдача - здається Help Insight не вказує документацію в scoped-модулях. Тобто якщо в звичайному Unit1.pas при наведенні на тип (клас) / метод тощо, перед яким є опис, в підказці це опис присутній, то в scoped-модулях (модулях з просторами імен) XML-опис ігнорується . Ну та й чорт з ним. Ще один цікавий факт в тому, що сам код задокументовано, проте в документації (довідці) описів немає . Але знову ж таки, повернемося до роботи безпосередньо з архівом. Для прикладу я накидав простеньке додаток - відкриття архіву, лістинг файлів всередині з висновком коефіцієнта стиснення + розархівування вибраних файлів.
Для роботи з zip-архівами використовується клас TZipFile. Для роботи з файлом можна використовувати два підходи: або вам потрібно знати про нутрощах архіву, або ви просто хочете розпакувати його цілком, без знання що там всередині і т.п. У першому випадку, вам буде потрібно використовувати методи Open / Close для відкриття файлу-архіву при початку роботи, і закриття в кінці. Розглянемо такий перший варіант. Наведений нижче приклад коду відкриває архів для читання, заповнює ZipView: TListView іменами файлів в архіві, для кожного файлу витягує його заголовок і визначає коефіцієнт стиснення за розміром стисненого та нестислого файлу, також визначає зашифрований файл чи ні. З приводу шифрованих архівів, то робота з ними за великим рахунком не підтримується (наскільки я зрозумів). Тобто якщо ваш архів запакований з використанням пароля, то розпакувати ви його не зможете. А для файлів входять в архів ви можете отримати заголовок, і визначити зашифрований файл чи ні. Нульовий біт поля flag структури TZipHeader визначає шифрування, тобто якщо він встановлений, то файл зашифрований. procedure TMainForm.OpenButtonClick (Sender: TObject); var i: integer; li: TListItem; exPath: string; zh: TZipHeader; ratio: real; begin // if not OpenDialog.Execute () then exit; // FZipFileName: = OpenDialog.FileName; FZipFileName: = 'C: \ Users \ teran \ Desktop \ radstudio_xe2_win_esd.zip'; exPath: = ExtractFilePath (FZipFileName) + ExtractFileName (FZipFileName); exPath: = ChangeFileExt (exPath, '') + '\'; try // check archive is valid if not FZip.IsValid (FZipFileName) then begin FZipFileName: = ''; exPath: = ''; exit; end; // Open ZIP-Archive and get ZIP-archive comment FZip.Open (FZipFileName, zmRead); CommentLabel.Caption: = Fzip.Comment; for i: = 0 to FZip.FileCount - 1 do begin // get i-th file headers zh: = fzip.FileInfo [i]; // add row to ListView li: = zipView.Items.Add (); li.Caption: = intToStr (i + 1); with li.SubItems do begin Add (FZip.FileName [i]); Add (Fzip.FileComment [i]); // calc compress-ratio if zh.UncompressedSize> 0 then ratio: = 1 - zh.CompressedSize / zh.UncompressedSize else ratio: = 0; Add (Format ( '%. 1f %%', [ratio * 100])); // check encryption (0-bit in Flag) if 0 in TIntegerSet (integer (zh.Flag)) then Add ( 'yes') else Add ( 'no'); end; end; // close archive FZip.Close (); finally FileEdit.Text: = FZipFileName; PathEdit.text: = exPath; end; end; В принципі такого функціоналу досить для простої підтримки zip-архівів в ваших додатках. Після того, як ми побачили вміст архіву, можемо спробувати розпакувати його. Як я вже говорив, в деяких випадках відкривати і закривати архів не потрібно. Так що якщо просто хочете повністю розпакувати архів, можна використовувати такий код: fzip: = TZipFile.Create (); try fzip.ExtractZipFile (FZipFileName, exPath); finally fzip.Free (); end; Але якщо як в нашому випадку потрібно витягти тільки вибрані файли, то необхідно знову відкрити файл архіву. procedure TMainForm.ExtractButtonClick (Sender: TObject); var exPath: string; i: integer; begin exPath: = PathEdit.Text; FZip.Open (FZipFileName, zmRead); try if not ForceDirectories (exPath) then exit; for i: = 0 to FZip.FileCount - 1 do begin if ZipView.Items [i] .Checked then FZip.Extract (i, exPath, true); end; finally FZip.Close (); end; end; Зауважу, що метод Extract має два перевантажених варіанти: або ви використовуєте індекс файлу (номер), або ім'я. З розпакуванням все ясно. Тепер про те, як створити архів, і додати туди файли. Щоб заархівувати, наприклад, директорію з файлами, необхідно створити екземпляр TZipFile, відкрити його для запису, і з допомогою методу Add додати туди всі необхідні файли. Нижче наведено фрагмент коду, який створює архів і додає в нього всі файли, що знаходяться в папці з проектом. При це файли додаються рекурсивно (тобто з вкладених директорій теж), що виконується файл не додається, та оскільки вихідний архів розташовується в папці з проектом, то він теж виключається. Не знаю як там було в ХЕ, але варто зауважити що в ХЕ2 директорія в яку складаються вихідні файли (ехе, dcu тощо) має вигляд Platform / Build configuration, тобто в моєму випадку Win32 / Debug. Звичайно, очевидно, що платформи в ХЕ не було, але мб варіант збірки і був, чого мені іноді сказати не вистачало в Delphi 2010 року (хоча звичайно це можна вказати в налаштуваннях). До слова сказати, ще в C ++ Builder'e 2007 output dir був Release або Debug, а в Delphi це прийшло тільки зараз (або в ХЕ) procedure TMainForm.CompressButtonClick (Sender: TObject); var z: TZipFile; path, f, zname, zfn: string; fa: TStringDynArray; begin path: = ExtractFileDir (Application.ExeName); z: = TZipFile.Create (); try zname: = path + '\ test.zip'; if FileExists (zname) then DeleteFile (zname); z.Open (zname, zmWrite); path: = TDirectory.GetParent (path); path: = TDirectory.GetParent (path); fa: = TDirectory.GetFiles (path, '*. *', TSearchOption.soAllDirectories); for f in fa do begin if (f = zname) or (f = Application.ExeName) then continue; zfn: = copy (f, length (path) + 2, length (f) - length (path) + 2); z.Add (f, zfn); end; z.Close (); finally z.Free (); end; end; Метод Add має кілька перевантажених версій. Найпростіша - вказує тільки ім'я файлу. Якщо ми скористаємося їй, то отримаємо архів з файлами, який не буде враховувати вихідну структуру дерева папок. Другий не обов'язковий параметр як раз таки і призначений, щоб задавати ім'я, під яким файл буде занесений в архів, тобто ми можемо поставити імена вкладених папок. Зібраний таким чином архів успішно розпаковується за допомогою 7z. Згадаймо про те, що шифровані архіви не підтримуються, тому якщо ви спробуєте створити в сторонньому архіваторі архів з паролем, то завантаживши його в за допомогою першого фрагмента коду, в стовпці encrypted отримаємо значення yes. Після розпакування такого архіву файли будуть нечитабельним. Насправді трохи дивно не бачити в даному класі методу для додавання директорії цілком - на зразок TZipFile.AddDirectory (path: string; recursive: boolean = true), але думаю в майбутньому і він з'явиться, а поки що реалізувати його руками, як показано вище не складає труднощів. Зазначу вельми важливий факт, що при виклику методу Add файл відразу починає оброблятися. Так що при додаванні великого файлу програма перестане відгукуватися. Так що висновок один - роботу з файлом архіву необхідно проводити в окремому потоці.