Отслеживание изменений в файловой системе и программирование потоков (threads)
Статья содержит пример использования потоков (threads) и отслеживания изменений в папке (каталоге) в файловой системе. К статье приложен пример исходного кода внешней компоненты (компилятор - Delphi 6) для 1С:Предприятие 7.7/8.0. | Автор статьи: romix | Редакторы: Последняя редакция №3 от 09.03.06 | История URL: http://kb.mista.ru/article.php?id=119 |
Ключевые слова: Внешняя компонента, Delphi, поток, thread, TThread, опрос директории, отслеживание изменений в файлах, FindFirstChangeNotification, WaitForSingleObject
Отслеживание изменений в директории
При реализации обмена между программами часто требуется проинформировать принимающую систему (в нашем случае, 1С:Предприятие) о том, что файлы пришли, и их пора принимать.
Как вариант, можно сканировать папку в процедуре обработки ожидания (например, делать это каждые N секунд).
Другой, пожалуй, более правильный способ - использовать системные функции FindFirstChangeNotification, FindNextChangeNotification и FindCloseChangeNotification из Windows API (аналогичные функции есть и в ОС Unix). В данном случае, оповещения об изменении в файловой системе выполняет ядро ОС, и не надо "проделывать дырку" на жестком диске постоянными к нему обращениями.
Что мы делаем из кода 1С
///////////////////////////////////////////////////////////////////////
Процедура ПриНачалеРаботыСистемы() //Предопределенная процедура 1С
ЗагрузитьВнешнююКомпоненту(vk_ChangeNotification.dll)
vk=СоздатьОбъект("AddIn.vk_ChangeNotification");
vk.ОтслеживатьПодкаталоги=0;
vk.НачатьКонтрольИзменений("c:\");
КонецПроцедуры
После такой инициализации в процедуру ОбработкаВнешнегоСобытия 1С будет приходить оповещения об изменении, в данном примере, папки "c:\". Если установить параметр vk.ОтслеживатьПодкаталоги=1, то еще и вложенных папок. Отслеживаться будут только изменения в именах файлов (например, появление нового файла в директории), но не изменение содержания файлов.
///////////////////////////////////////////////////////////////////////
Процедура ОбработкаВнешнегоСобытия(Источник,Событие,Данные)//Предопределенная процедура 1С
//Глобальный обработчик внешнего события
Сообщить("Внешнее событие: Источник="+Источник+" Событие="+Событие+" Данные="+Данные);
КонецПроцедуры
Чтобы прекратить опрос изменений в директории, доступна функция
///////////////////////////////////////////////////////////////////////
Процедура ПриЗавершенииРаботыСистемы()
vk.ЗакончитьКонтрольИзменений();
КонецПроцедуры // ПриЗавершенииРаботыСистемы
Процедура потока в Delphi
//Процедура потока
procedure TMyThread.Execute;
var r: Cardinal;
var fn : THandle;
begin
fn:=0;
try
fn := FindFirstChangeNotification(pChar(MyObject.DirName), MyObject.CheckSubfolders, FILE_NOTIFY_CHANGE_FILE_NAME);
if fn=INVALID_HANDLE_VALUE then
RaiseLastOSError;
repeat
r := WaitForSingleObject(fn,2000);
if r = WAIT_OBJECT_0 then
MyObject.iEvent.ExternalEvent(c_AddinName, 'FolderChange', MyObject.DirName);
if not FindNextChangeNotification(fn) then begin
RaiseLastOSError;
break;
end;
until Terminated;
FindCloseChangeNotification(fn);
except
on E:Exception do begin
try
FindCloseChangeNotification(fn);
except
end;
MyObject.ShowErrorLog('Ошибка контроля папки: '+E.Message);
end;
end;
end;
Процедура генерирует события (ExternalEvent), как только обнаружит изменения в указанной папке файловой системы. Параметр FILE_NOTIFY_CHANGE_FILE_NAME указывает на необходимость контролировать имена файлов. См. справку по WinAPI (например, на диске MSDN), чтобы узнать, какие варианты этого параметра есть еще.
Инициализация потока
Для потока я определяю отдельный класс, унаследованный от TThread.
type
TMyThread = class(TThread) //Новый класс
private
MyObject: AddInObject;
protected
constructor Create(prm_Obj:AddInObject);
procedure Execute; override;
end;
Конструктор класса описан следующим образом:
constructor TMyThread.Create(prm_Obj:AddInObject);
begin
inherited Create(False);
MyObject:=prm_Obj;
end;
Объект внешней компоненты содержит поле MyThread (тип - TThread).
В методе ВК я инициализирую переменную потока так:
MyThread := TMyThread.Create(Self);
В этот момент начинает выполняться наша процедура потока:
procedure TMyThread.Execute;
И выполняется она до тех пор, пока я не дам команду потоку остановиться:
MyThread.Terminate; //завершаем поток
MyThread.WaitFor; //ждем, когда поток закончит свое выполнение
MyThread.Destroy;
MyThread:=nil;
Поток может изловить ситуацию, что его хотят завершить, прочитав свойство Terminated:
repeat
//...
until Terminated;
Вызов MyThread.WaitFor ждет, когда поток завершит свою работу, после чего переменную можно разрушать - MyThread.Destroy.
Заключение
Мы рассмотрели работу с потоком исполнения во внешней компоненте 1С:Предприятие.
Поток выполняет полезное действие - отслеживает изменение файлов в директории.
Вы можете заставить поток делать что-то другое: например, опрашивать FTP, почтовый ящик, опрашивать сканер штрихкодов или выполнять другие полезные действия в автоматическом режиме.
Ссылки
http://ad.cctpu.edu.ru/SSP/Prof/index.html
Книга знаний: Работа с последовательным (COM, RS-232) портом из 1С:Предприятие 7.7 и 8.0
Внешняя компонента с исходным кодом и тестовой конфигурацией для скачивания:
http://x-romix.narod.ru/vk_ChangeNotification.rar
(скачивать ЛЕВОЙ кнопкой мыши, 97 килобайт).
No comments:
Post a Comment