Компонент zip-файла, встроенный в XE2, сделает это.
Существует перегруженный метод Open
, который получает TStream
в качестве входных параметров.
Для извлечения отдельных файлов вы можете вызвать перегруженный метод Read
, передав имя файла, который вы хотите извлечь. Извлеченный файл возвращается как новый экземпляр TStream
. Вы можете использовать CopyFrom
в этом экземпляре для передачи извлеченного файла в ваш поток.
var
ZipFile: TZipFile;
DownloadedStream, DecompressionStream, MyStream: TStream;
LocalHeader: TZipHeader;
...
ZipFile := TZipFile.Create;
try
ZipFile.Open(DownloadedStream, zmRead);
ZipFile.Read('myzippedfile', DecompressionStream, LocalHeader);
try
MyStream.CopyFrom(DecompressionStream, DecompressionStream.Size);
finally
DecompressionStream.Free;
end;
finally
ZipFile.Free;
end;
Обратите внимание, что я не тестировал этот код, я просто написал его на основе исходного кода для TZipFile
и документации, содержащейся в этом исходном коде. В этом может быть несколько складок, но если код ведет себя так, как объявлено, он полностью соответствует вашим потребностям.
Хорошо, теперь я проверил это, потому что мне было любопытно. Вот программа, которая показывает, что все это работает так, как рекламируется:
program ZipTest;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
System.Classes,
System.Zip;
procedure ExtractToFile(
const ZipFileName: string;
const ZippedFileIndex: Integer;
const ExtractedFileName: string
);
var
ZipFile: TZipFile;
DownloadedStream, DecompressionStream, OutputStream: TStream;
LocalHeader: TZipHeader;
begin
DownloadedStream := TFileStream.Create(ZipFileName, fmOpenRead);
try
ZipFile := TZipFile.Create;
try
ZipFile.Open(DownloadedStream, zmRead);
ZipFile.Read(ZippedFileIndex, DecompressionStream, LocalHeader);
try
OutputStream := TFileStream.Create(ExtractedFileName, fmCreate);
try
OutputStream.CopyFrom(DecompressionStream, DecompressionStream.Size);
finally
OutputStream.Free;
end;
finally
DecompressionStream.Free;
end;
finally
ZipFile.Free;
end;
finally
DownloadedStream.Free;
end;
end;
begin
try
ExtractToFile('C:\desktop\test.zip', 0, 'C:\desktop\out.txt');
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Обратите внимание, что я извлекал по индексу, а не по имени файла, так как это было более удобно для меня. И я использовал потоки файлов, а не потоки памяти, которые, я полагаю, вы бы использовали. Однако, поскольку методы TZipFile
работают с TStream
, я уверен, что код будет работать с потоками любой формы.
Это последний из серии вопросов о ZIP-файлах. Я знаю, что вы используете XE2, и мне интересно, почему вы, похоже, неохотно используете встроенный класс ZIP, который предоставляет XE2. Я не видел ничего, что указывало бы на то, что оно не будет соответствовать вашим требованиям. Фактически, именно эта способность работать напрямую с потоками позволяет мне чувствовать, что она имеет достаточную общность для любого приложения.