![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Как грамотно организовать копирование файлов по локалке. (+) [D7, WinXP]
EarlVadim © (2006-01-18 10:42:00)Есть необходимость периодически опрашивать удалённые хосты (с доступом естессно) на наличие в сети, и в положительном случае, копировать с них определённый файл.
Сейчас тупо используеься COPYFILE(SFN,TFN); Проблема в том, что процесс копирования файла "примораживает" программу, а если хост недоступен, то это уже на 5-10 секунд "заморозка". Ни свернуть, ни закрыть, ничего. Файл небольшой - до 100Кб.
Как это НАДО делать, чтобы процесс опроса-копирования действительно был ФОНОВЫМ?
EarlVadim (2006-01-25 11:20:00) [21]Thread.Resume; я пробовал и раньше. Сейчас сделал все как написано.
Проставил два брейка.
Результат:
Ни на BEGIN в Execute, ни на BEGIN в ProcessFile выполнение не останавливается, -> ход выполнения до них не добирается.
Может D7 глючит? Хотя в другой версии той же проги у меня работает код без WaitFor. Но та версия сама по себе меня не устраивает.
Придётся с нуля проект создавать, видимо.
Digitman (2006-01-25 09:38:00) [22]
> без Thread.WaitFor; Execute вообще не факт что получит управление
получит, если поток не создан как suspended.
и это факт.
установи брейкпойнт
procedure MyThread.Execute;
begin //<- ЗДЕСЬ
..
end;
вызови
Thread := MyThread.Create(..., False);
и убедись в "факте".
Единственное что я упустил в [11] и что важнов том контексте :
//поток создается как suspended для того чтобы перед началом его выполнения можно было назначить нужные нам св-ва
Thread := MyThread.Create(... конкретный URL файла .., True);
//поток должен разрушить себя сам после завершения выполнения
Thread.FreeOnTerminate := True;
//назначение обработчика события
Thread.OnTerminate := ProcessFile; //назначенный обработчик события OnTerminate будет вызван в осн.потоке процесса сразу после завершения метода MyThread.Execute;
//и наконец "пробуждаем" поток !
Thread. Resume;
EarlVadim (2006-01-24 18:23:00) [23]Скажу больше, без Thread.WaitFor; Execute вообще не факт что получит управление. У меня в 4-х вариантах пробы потока, так вот работают потоки в 2-х, а в 2-х других - НЕТ. Все вызовы идентичны, голова уже пухнет...
EarlVadim (2006-01-24 17:47:00) [24]Digitman © (24.01.06 17:26) [13]
По шагам прошёл, не передаётся выполнение туда и всё тут.
В общем, в печали я.
Digitman (2006-01-24 17:26:00) [25]
> EarlVadim © (24.01.06 17:12) [12]
отладчик тебе в руки
EarlVadim (2006-01-24 17:12:00) [26]Digitman © (20.01.06 13:45) [11]
Нифига не работает такой вариант.
ProcessFile - не выполняется.
Digitman (2006-01-20 13:45:00) [27]
> Или есть другие способы?
Конечно же есть.
WaitFor был простейшим решением для оригинального примера в [7].
В изложенном же в [10] случае можно поступить, например, так:
MyThread = class(TThread)
private
FParameter: String;
FResult: String;
protected
procedure Execute; override;
public
constructor Create(DownloadURL: String; Suspended: Boolean);
property DownloadedFileName: String read FResult;
end;
..
constructor MyThread.Create(DownloadURL: String; Suspended: Boolean);
begin
FParameter := DownloadURL;
inherited Create(Suspended);
end;
procedure MyThread.Execute;
begin
try
.. попытка закачки файла по локатору в FParameter ..
FResult := ... полный путь к закачанному файлу .. //закачка успешна
except
.. закачка неуспешна ..
end;
end;
...
Procedure TMainForm.ProcessFile(Sender: TObject);
begin
with TMyThread(Sender) do begin
if DownloadedFileName <> '' then //закачка успешна
Labels[..].Caption:= DownloadedFileName;// эмуляция "обработки файла" для примера
end;
end;
Thread := MyThread.Create(... конкретный URL файла .., True);
Thread.FreeOnTerminate := True;
Thread.OnTerminate := ProcessFile; //назначенный обработчик события OnTerminate будет вызван в осн.потоке процесса сразу после завершения метода MyThread.Execute;
// Labels[iz].Caption:= Thread.ExecResult;
// Thread.Destroy;
EarlVadim (2006-01-20 10:15:00) [28]Digitman © (19.01.06 09:59) [8]
Этсамое.... Ну прикрутил я всё в свою прогу, все работает, но эффекта положительного нет. Все дело в Thread.WaitFor;
Обясняю: в теле MainForm организован цикл "по всем хостам читать файл и данные файла хитрым образом обрабатывать". Чтение файлов я воткнул в поток, а вот обработка у меня в MainForm. Так вот, пока файл по сети читаясь тупит, программа, следуя WaitFor тоже приморожена. Но если WaitFor убрать, то естессно нифига неработает. Какой для этого выход?
Мне видится так, что я должен в поток переместить всю процедуру (и чтения файлов и их обработку и вывод результатов в окно программы).
Или есть другие способы?
EarlVadim (2006-01-19 10:04:00) [29]Digitman © (19.01.06 09:59) [8]
Спасибо... Ведь как все просто, но сам не допрёшь...
Digitman (2006-01-19 09:59:00) [30]MyThread = class(TThread)
private
FParameter: Integer;
FResult: String;
protected
procedure Execute; override;
public
constructor Create(Parameter: Integer);
property MyResult: String read FResult;
end;
..
constructor MyThread.Create(Parameter: Integer);
begin
FParameter: Integer;
inherited Create(False);
end;
procedure MyThread.Execute;
begin
FResult := IntToStr(FParameter);
end;
...
Procedure TMainForm.ReadData(Sender: TObject);
Var iz : integer;
begin
For iz:= 0 to 9 do BEGIN
Thread := MyThread.Create(iz);
Thread.WaitFor;
Labels[iz].Caption:= Thread.ExecResult;
Thread.Destroy;
END;
end;
EarlVadim (2006-01-19 09:37:00) [31]2 Digitman © (18.01.06 17:32) [6]
Ну с принципом я в общем-то разобрался.
Простая прога с потоком - работает.
Вставляю теже самые компоненты, процедуры, классы в свою программу, поток не работает. (Хотя в теле потока для начала все предельно просто)
unit MyThreadU;
interface
uses
Classes, Windows, SysUtils, Variants;
type
MyThread = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
public
i1 : integer;
s1 : string;
end;
implementation
procedure MyThread.Execute;
begin
s1:= IntToStr(i1);
end;
end
Соответственно в главной проге
Procedure TMainForm.ReadData(Sender: TObject);
Var iz : integer;
begin
Thread := MyThread.Create(true);
Thread.Priority := tpLowest;
Thread.FreeOnTerminate:= false;
For iz:= 0 to 9 do BEGIN
Thread.i1:= iz;
Thread.Resume;
Labels[iz].Caption:= Thread.s1;
END;
Thread.Destroy;
end;
Чтоже у меня не правильно? Пробовал разные варианты. И Create/Destroy ставил в тело цикла. И Create(false) писал - ничего. "s1' всегда = '';
Digitman (2006-01-18 17:32:00) [32]реализуй код доп.потока, который собственно и будет заниматься копированием файла.
ссылку на местоположение файла передавай параметром при конструировании потока
EarlVadim (2006-01-18 12:41:00) [33]2 Fay © (18.01.06 11:45) [4]
Я тут в сети нашёл пример создания приложения с двумя потоками.
http://rusasdatabase.narod.ru/threads.html
Все работает, все ОК. Но вот вопрос, как прикрутить это все себе.
Объясните принцип. Вся программа должна быть одним потоком, а CopyFile - вторым, Или просто создать в программе один поток с CopyFile?
Fay (2006-01-18 11:45:00) [34]2 EarlVadim © (18.01.06 11:39) [3]
CreateThread | свой наследник TThread
EarlVadim (2006-01-18 11:39:00) [35]Не сталкивался.
Если не в лом, как делать?
Fay (2006-01-18 11:37:00) [36]2 EarlVadim © (18.01.06 10:42)
Вытащи в отдельный поток.
EarlVadim (2006-01-18 10:45:00) [37]Да, чуть не забыл, Сеть- MS на TCP/IP