Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2011.04.10;
Скачать: CL | DM;

Вниз

посоветуйте, как организовать алгоритм   Найти похожие ветки 

 
пишу_курсовой   (2011-01-12 15:53) [0]

приложение, в определенные моменты извлекает из архивов (.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 16:07) [1]

Отдельная процера нужна в случае многократного использования одного и того же алгоритма. А это как раз твой случай, поскольку кол-во файлов в архиве заранее неизвестно, что предполагает услловно-циклическое обращение к алгоритму извлечения файла.
Другой вопрос что при массированном извлечении, вожможно, есть резон вынести создание объекта-стрима в вызывающий код.


 
пишу_курсовой   (2011-01-12 16:12) [2]


> есть резон вынести создание объекта-стрима в вызывающий
> код.


т.е. параметр AStream сделать как var?


 
Сергей М. ©   (2011-01-12 16:16) [3]

Вот как раз не var и не out.

var и out нужны когда объект-результат создается в вызываемом коде, т.е. именно как у тебя проиллюстрировано в п.1


 
пишу_курсовой   (2011-01-12 16:23) [4]

как тогда передать в вызываемый код объект-стрим, создаваемый в вызывающем коде, не используя var, в инете видел много примеров такой организаций только с использованием var


 
Сергей М. ©   (2011-01-12 16:31) [5]


> как тогда передать в вызываемый код объект


Для этого нужно совсем малое - понимание того факта что дельфийские данные объектного типа есть суть указатели. Передавая факт.параметром значение переменной ms: TStream ты по сути передаешь указатель на местоположение в памяти конкретного объекта класса TStream. Нет никакой нужды передавать указатель на указатель, помечая форм.параметр как var или out.


 
пишу_курсовой   (2011-01-12 16:37) [6]

вот я ступил!!!, спасибо


 
пишу_курсовой   (2011-01-12 16:42) [7]

забыл спросить, на интерфейсы такая же логика распространяется? к примеру у меня есть некий интерфейс IMyInterface который я передаю в процедуру/функцию и чтот-то делаю. объявление как var будет лишним?


 
Ega23 ©   (2011-01-12 16:45) [8]


> как var будет лишним?

да


 
Сергей М. ©   (2011-01-12 16:48) [9]

да
объект, представленный интерфейсом, - это тоже ссылка.


 
Юрий Зотов ©   (2011-01-12 16:59) [10]

except
 raise Exception.CreateFmt(C_CANNOT_LOAD_FILE, [Afile_name, Pack.FileName]);
 AStream.Free; // Эта строка никогда не выполнится.
end;


Поменяйте местами.


 
пишу_курсовой   (2011-01-12 17:02) [11]

спс. не заметил, AStream.Free вообщем-то уже не нужен, раз объект стрим создается вне.


 
Юрий Зотов ©   (2011-01-12 17:18) [12]


> 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:31) [13]

И, наверное, стоит показать текст сообщения о реально возникшей ошибке:

...
 try
   APack.ExtractToStream(AStream);
 except
   on E: Exceprtion do
     raise Exception.CreateFmt(..., [Afile_name, APack.FileName, E.Message]);
 end;
...

Иначе истинная причина ошибки окажется "спрятанной".


 
пишу_курсовой   (2011-01-12 17:35) [14]


> Причем используя вложенный блок (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:46) [15]


> На различных этапах (отдельные процедуры) после извлечения
> будут выполнятся различные действия (определенные типы файлов
> имеют определенное функциональное назначение), где-то нужно
> получить размер извлеченного файла, где-то его контрольную
> сумму, где-то стрим будет разбиваться на отдельные куски
> которые будут записываться в другой стрим


Вот для всего этого и написано:
... // Работаем с потоком AStream

Возможно, есть смысл породить потомка TZipFoge и добавить в него public свойство Stream - тогда к этому свойству можно будет обращаться везде. Соответственно, в конструкторе этот Stream надо создать, а в деструкторе - уничтожить. Также нужно будет написать метод записи в этот Stream, а в нем перед вызовом ExtractToStream вызывать Clear.



Страницы: 1 вся ветка

Текущий архив: 2011.04.10;
Скачать: CL | DM;

Наверх




Память: 0.51 MB
Время: 0.011 c
2-1294720735
DROWSY
2011-01-11 07:38
2011.04.10
Как в ячейке грида выводить текст, если значение поля


15-1293485386
Юрий
2010-12-28 00:29
2011.04.10
С днем рождения ! 28 декабря 2010 вторник


15-1291298849
Медвежонок Пятачок
2010-12-02 17:07
2011.04.10
ну а в самом-то деле как на самом деле обстоят дела с азотом?


15-1292731851
Дмитрий С
2010-12-19 07:10
2011.04.10
К вопросу планетах.


2-1294871283
Ghost del vonte
2011-01-13 01:28
2011.04.10
Проблема при удалении последней вкладки на TabSet