![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
посоветуйте, как организовать алгоритм
пишу_курсовой © (2011-01-12 15:53:00)приложение, в определенные моменты извлекает из архивов (.zip) файлы и выполняет определенные действия с ними. В ТЗ сказано, если не удалось извлеч файл, райсить эксепшен - "Не удалось извлечь файл "<имя_файла_в_пакете_обновления>" из пакета обновления" "<имя_файла_пакета_обновления>". Вопрос: Как более гибко и оптимально организовать алгоритм извлечения.
1. Написать отдельную процедуру, возвращающую в качестве out-параметра TStream (извлекаемый файл)
procedure pack_file_get(APack: TZipFoge; const Afile_name: string;
out AStream);
begin
AStream := TMemoryStream.Create;
try
APack.ExtractToStream(AStream);
except
raise Exception.CreateFmt(C_CANNOT_LOAD_FILE,
[Afile_name, APack.FileName]);
AStream.Free;
end;
end;
2. Обойтись без процедуры, и напряму в коде создавать TStream, извлекать в него и обрабатывать try..except
3. Как бы сделали вы?
Юрий Зотов (2011-01-12 17:46:00) [1]
> На различных этапах (отдельные процедуры) после извлечения
> будут выполнятся различные действия (определенные типы файлов
> имеют определенное функциональное назначение), где-то нужно
> получить размер извлеченного файла, где-то его контрольную
> сумму, где-то стрим будет разбиваться на отдельные куски
> которые будут записываться в другой стрим
Вот для всего этого и написано:
... // Работаем с потоком AStream
Возможно, есть смысл породить потомка TZipFoge и добавить в него public свойство Stream - тогда к этому свойству можно будет обращаться везде. Соответственно, в конструкторе этот Stream надо создать, а в деструкторе - уничтожить. Также нужно будет написать метод записи в этот Stream, а в нем перед вызовом ExtractToStream вызывать Clear.
пишу_курсовой (2011-01-12 17:35:00) [2]
> Причем используя вложенный блок (try-except внутри try-finally)
> эти две процедуры можно объединить в одну - и это, пожалуй,
> будет самое правильное решение.
>
> procedure MyProc(APack: TZipFoge; Afile_name: string);
> var
> AStream: TMemoryStream;
> begin
> AStream := TMemoryStream.Create;
> try
> try
> APack.ExtractToStream(AStream);
> except
> raise Exception.CreateFmt(C_CANNOT_LOAD_FILE, [Afile_name,
> APack.FileName]);
> end;
> ... // Работаем с потоком AStream
> finally
> AStream.Free;
> end;
> end;
этот вариант отпадает, должна быть возможность возвращать Stream. На различных этапах (отдельные процедуры) после извлечения будут выполнятся различные действия (определенные типы файлов имеют определенное функциональное назначение), где-то нужно получить размер извлеченного файла, где-то его контрольную сумму, где-то стрим будет разбиваться на отдельные куски которые будут записываться в другой стрим
Юрий Зотов (2011-01-12 17:31:00) [3]И, наверное, стоит показать текст сообщения о реально возникшей ошибке:
...
try
APack.ExtractToStream(AStream);
except
on E: Exceprtion do
raise Exception.CreateFmt(..., [Afile_name, APack.FileName, E.Message]);
end;
...
Иначе истинная причина ошибки окажется "спрятанной".
Юрий Зотов (2011-01-12 17:18:00) [4]
> 1. Написать отдельную процедуру, возвращающую в качестве
> out-параметра TStream (извлекаемый файл)
Отдельная процедура - это правильно. Но чтобы сама она создавала объект и возвращала его - это не очень хороший стиль (чреват утечками памяти). Правильнее создавать и уничтожать объект в рамках одной и той же процедуры, причем в блоке try-finally:
procedure pack_file_get(APack: TZipFoge; Afile_name: string; AStream: TMemoryStream);
begin
try
APack.ExtractToStream(AStream);
except
raise Exception.CreateFmt(C_CANNOT_LOAD_FILE, [Afile_name, APack.FileName]);
end;
end;
Вызов такой:
procedure MyProc(APack: TZipFoge; Afile_name: string);
var
AStream: TMemoryStream;
begin
AStream := TMemoryStream.Create;
try
pack_file_get(APack, Afile_name, AStream);
... // Работаем с потоком AStream
finally
AStream.Free;
end;
end;
Причем используя вложенный блок (try-except внутри try-finally) эти две процедуры можно объединить в одну - и это, пожалуй, будет самое правильное решение.
procedure MyProc(APack: TZipFoge; Afile_name: string);
var
AStream: TMemoryStream;
begin
AStream := TMemoryStream.Create;
try
try
APack.ExtractToStream(AStream);
except
raise Exception.CreateFmt(C_CANNOT_LOAD_FILE, [Afile_name, APack.FileName]);
end;
... // Работаем с потоком AStream
finally
AStream.Free;
end;
end;
пишу_курсовой (2011-01-12 17:02:00) [5]спс. не заметил, AStream.Free вообщем-то уже не нужен, раз объект стрим создается вне.
Юрий Зотов (2011-01-12 16:59:00) [6]
except
raise Exception.CreateFmt(C_CANNOT_LOAD_FILE, [Afile_name, Pack.FileName]);
AStream.Free; // Эта строка никогда не выполнится.
end;
Поменяйте местами.
Сергей М. (2011-01-12 16:48:00) [7]да
объект, представленный интерфейсом, - это тоже ссылка.
Ega23 (2011-01-12 16:45:00) [8]
> как var будет лишним?
да
пишу_курсовой (2011-01-12 16:42:00) [9]забыл спросить, на интерфейсы такая же логика распространяется? к примеру у меня есть некий интерфейс IMyInterface который я передаю в процедуру/функцию и чтот-то делаю. объявление как var будет лишним?
пишу_курсовой (2011-01-12 16:37:00) [10]вот я ступил!!!, спасибо
Сергей М. (2011-01-12 16:31:00) [11]
> как тогда передать в вызываемый код объект
Для этого нужно совсем малое - понимание того факта что дельфийские данные объектного типа есть суть указатели. Передавая факт.параметром значение переменной ms: TStream ты по сути передаешь указатель на местоположение в памяти конкретного объекта класса TStream. Нет никакой нужды передавать указатель на указатель, помечая форм.параметр как var или out.
пишу_курсовой (2011-01-12 16:23:00) [12]как тогда передать в вызываемый код объект-стрим, создаваемый в вызывающем коде, не используя var, в инете видел много примеров такой организаций только с использованием var
Сергей М. (2011-01-12 16:16:00) [13]Вот как раз не var и не out.
var и out нужны когда объект-результат создается в вызываемом коде, т.е. именно как у тебя проиллюстрировано в п.1
пишу_курсовой (2011-01-12 16:12:00) [14]
> есть резон вынести создание объекта-стрима в вызывающий
> код.
т.е. параметр AStream сделать как var?
Сергей М. (2011-01-12 16:07:00) [15]Отдельная процера нужна в случае многократного использования одного и того же алгоритма. А это как раз твой случай, поскольку кол-во файлов в архиве заранее неизвестно, что предполагает услловно-циклическое обращение к алгоритму извлечения файла.
Другой вопрос что при массированном извлечении, вожможно, есть резон вынести создание объекта-стрима в вызывающий код.