Thursday, June 15, 2006

Отслеживание изменений в файловой системе и программирование потоков (threads)

Отслеживание изменений в файловой системе и программирование потоков (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: