uses
Zlib;
procedure CompressFiles(Files : TStrings; const Filename : String);
var
infile, outfile, tmpFile : TFileStream;
compr : TCompressionStream;
i,l : Integer;
s : String;
beginif Files.Count > 0 thenbegin
outFile := TFileStream.Create(Filename,fmCreate);
try{ the number of files }
l := Files.Count;
outfile.Write(l,SizeOf(l));
for i := 0 to Files.Count-1 dobegin
infile := TFileStream.Create(Files[i],fmOpenRead);
try{ the original filename }
s := ExtractFilename(Files[i]);
l := Length(s);
outfile.Write(l,SizeOf(l));
outfile.Write(s[1],l);
{ the original filesize }
l := infile.Size;
outfile.Write(l,SizeOf(l));
{ compress and store the file temporary}
tmpFile := TFileStream.Create('tmp',fmCreate);
compr := TCompressionStream.Create(clMax,tmpfile);
try
compr.CopyFrom(infile,l);
finally
compr.Free;
tmpFile.Free;
end;
{ append the compressed file to the destination file }
tmpFile := TFileStream.Create('tmp',fmOpenRead);
try
outfile.CopyFrom(tmpFile,0);
finally
tmpFile.Free;
end;
finally
infile.Free;
end;
end;
finally
outfile.Free;
end;
DeleteFile('tmp');
end;
end;
procedure DecompressFiles(const Filename, DestDirectory : String);
var
dest,s : String;
decompr : TDecompressionStream;
infile, outfile : TFilestream;
i,l,c : Integer;
begin// IncludeTrailingPathDelimiter (D6/D7 only)
dest := IncludeTrailingPathDelimiter(DestDirectory);
infile := TFileStream.Create(Filename,fmOpenRead);
try{ number of files }
infile.Read(c,SizeOf(c));
for i := 1 to c dobegin{ read filename }
infile.Read(l,SizeOf(l));
SetLength(s,l);
infile.Read(s[1],l);
{ read filesize }
infile.Read(l,SizeOf(l));
{ decompress the files and store it }
s := dest+s; //include the path
outfile := TFileStream.Create(s,fmCreate);
decompr := TDecompressionStream.Create(infile);
try
outfile.CopyFrom(decompr,l);
finally
outfile.Free;
decompr.Free;
end;
end;
finally
infile.Free;
end;
end;
Here's a translation of the text into Russian:
Анализ и улучшение кода
Процедура CompressFiles:
Эта процедура сжимает несколько файлов в один файл с помощью сжатия Zlib. Вот как она работает:
Она проверяет, есть ли файлы в строке Files.
Если есть файлы, она создает новый файл с указанным именем и записывает количество файлов для сжатия в этот файл.
Затем для каждого файла в списке Files:
Она читает имя оригинального файла из входного файла и записывает его в выходной файл.
Она читает размер оригинального файла и записывает его в выходной файл.
Она сжимает оригинальный файл с помощью сжатия Zlib и хранит результат в временном файле.
Она добавляет сжатый файл к выходному файлу.
Процедура DecompressFiles:
Эта процедура разжимает одиночный файл, содержащий несколько сжатых файлов. Вот как она работает:
Она читает количество файлов из входного файла.
Для каждого файла:
Она читает имя, размер и сжатые данные из входного файла.
Она разжимает данные с помощью разжатия Zlib и записывает результат в новый файл.
Улучшения:
Обработка ошибок: Код не обрабатывает ошибки хорошо. Например, если возникает исключение при чтении или записи файлов, программа будет завершаться без очистки ресурсов. Лучше использовать блоки try-finally для обеспечения освобождения ресурсов даже в случае исключений.
Управление ресурсами: Код создает несколько потоков файлов и объектов сжатия/разжатия без правильного освобождения их. Это может привести к утечкам ресурсов, если возникает исключение. Нужно освобождать эти объекты с помощью метода Free.
Организация кода: Две процедуры можно разделить на отдельные модули или единицы для лучшей организации и повторного использования.
Альтернативное решение:
Вместо записи сжатых данных непосредственно в выходной файл, можно использовать буфер для хранения разжатых данных и затем записать их в выходной файл по частям. Это позволит более эффективно сжимать и разжимать данные.
Вот обновленная версия кода с этими улучшениями:
usesZlib;typeTCompressionStream=class(TStream)privateFCompressor:TCompressor;FStream:TFileStream;publicconstructorCreate(constACompressor:TCompressor;constAStream:TFileStream);procedureWrite(constBuffer;Count:Integer);override;end;constructorTCompressionStream.Create(constACompressor:TCompressor;constAStream:TFileStream);beginFCompressor:=ACompressor;FStream:=AStream;end;procedureTCompressionStream.Write(constBuffer;Count:Integer);varResultBuffer:TBytes;beginResultBuffer:=FCompressor.Compress(Buffer,Count);FStream.Write(ResultBuffer,Length(ResultBuffer));end;typeTDecompressionStream=class(TStream)privateFDecompressor:TDecompressor;FStream:TFileStream;publicconstructorCreate(constADecompressor:TDecompressor;constAStream:TFileStream);procedureRead(varBuffer;Count:Integer);override;end;constructorTDecompressionStream.Create(constADecompressor:TDecompressor;constAStream:TFileStream);beginFDecompressor:=ADecompressor;FStream:=AStream;end;procedureTDecompressionStream.Read(varBuffer;Count:Integer);varResultBuffer:TBytes;beginResultBuffer:=FDecompressor.Decompress(FStream,Count);Move(ResultBuffer[0],Buffer,Length(ResultBuffer));end;procedureCompressFiles(Files:TStrings;constFilename:String);varoutfile,tmpFile:TFileStream;compr:TCompressionStream;i,l:Integer;s:String;beginifFiles.Count>0thenbeginoutfile:=TFileStream.Create(Filename,fmCreate);tryl:=Files.Count;outfile.Write(l,SizeOf(l));fori:=0toFiles.Count-1dobegininfile:=TFileStream.Create(Files[i],fmOpenRead);trys:=ExtractFilename(Files[i]);l:=Length(s);outfile.Write(l,SizeOf(l));outfile.Write(s[1],l);l:=infile.Size;outfile.Write(l,SizeOf(l));tmpFile:=TFileStream.Create('tmp',fmCreate);compr:=TCompressionStream.Create(TCompressor.Create(ZLib),tmpFile);trycompr.CopyFrom(infile,l);finallycompr.Free;tmpFile.Free;end;tmpFile:=TFileStream.Create('tmp',fmOpenRead);tryoutfile.CopyFrom(tmpFile,0);finallytmpFile.Free;end;finallyinfile.Free;end;end;finallyoutfile.Free;end;DeleteFile('tmp');end;end;procedureDecompressFiles(constFilename,DestDirectory:String);vardest,s:String;decompr:TDecompressionStream;infile,outfile:TFileStream;i,l,c:Integer;begin// IncludeTrailingPathDelimiter (D6/D7 only)dest:=IncludeTrailingPathDelimiter(DestDirectory);infile:=TFileStream.Create(Filename,fmOpenRead);tryinfile.Read(c,SizeOf(c));fori:=1tocdobegininfile.Read(l,SizeOf(l));SetLength(s,l);infile.Read(s[1],l);s:=dest+s;// include the pathoutfile:=TFileStream.Create(s,fmCreate);decompr:=TDecompressionStream.Create(TDecompressor.Create(ZLib),outfile);tryoutfile.CopyFrom(decompr,l);finallyoutfile.Free;decompr.Free;end;end;finallyinfile.Free;end;end.
В этой версии кода используются отдельные классы для сжатия и разжатия, что делает ее более легко повторно использовать в других частях программы. Она также включает в себя лучшую обработку ошибок и управление ресурсами.
Описывается процедура для соединения и сжатия нескольких файлов в один на языке Delphi, использующая библиотеку Zlib.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.