Форум » [x]Harbour » Как правильно ловить обновки ? » Ответить

Как правильно ловить обновки ?

Dima: Есть сетевая папка. В неё прилетают сканы документов из разных источников , в том числе могут создаваться папки. Каким образом правильно ловить что прилетело и куда , что бы после писать эту инфу в базу , для поиска этих самых сканов. Сейчас по RPC использую для поиска hb_DirScan , но чем больше сканов тем тормознее такой поиск. Сейчас их живет около 100 000.

Ответов - 20

Haz: Dima пишет: Каким образом правильно ловить что прилетело и куда , что бы Дим, как вариант, использовать на удаленной машине возможности операционки, а именно процедуру сторожа изменения в файловой системы наблюдаемого каталога и по ней писать в журнал. Подключившись читаешь журнал в котором все новое и обнуляешь его Петр подробно разжевал тему в посте 1252

Dima: Игорь ты вот про это ? http://clipper.borda.ru/?1-4-0-00001144-000-0-0-1471346473 Но там только факт изменения можно поймать если я верно понял а нужно ловить имя файла и куда он упал а какой файл (имя) и куда упал не известно.

Haz: Dima пишет: ты вот про это да , но про имя не помню , можно ли словить. Скорее всего должен быть способ. Гляну


Dima: я так понял нужна функция ReadDirectoryChangesW для этого https://delphisources.ru/pages/faq/base/read_directory_changes_w.html или глянуть в сторону WMI :) https://social.technet.microsoft.com/Forums/ie/en-US/445f54d2-3b0c-4984-86e0-22f5734b368a/vbscript-wmi-filesystemwatcher?forum=ITCG

SergKis: Dima пишет Сейчас их живет около 100 000 Что так сложно ? Держи папку пустой, принятые делай move в др. папку принятых, можешь по ним журнал вести и сортировать куда, кому кинуть сразу. Если доступ к папке не по RPC, а FTP ... замучаешься глотать такой список файлов. PS При таком приеме, перед move, можно проверить правильность КС, тест zip и т.д

Haz: Dima пишет: я так понял нужна функция ReadDirectoryChangesW для этого Да, это оно. Но в харбуре примеров использования не встречал к сожалению

Dima: SergKis пишет: Держи папку пустой Сергей файлы прилетают с разных мест да и прога не моя что их туда ложит , с планшетов в основном прилетает , но мысль интересная и подумаю.

Dima: Работает однако WMI Только пока не понял как запросу правильно написать что бы слушал и подкаталоги внутри опрашиваемой папки. Есть мысли у кого ? [pre2] Proc Main local objWMI local intInterval:= "2" local strDrive:= "C:" local strFolder:= "\\POCKET\\skans\\" local elem objWMI:=WmiService() colEvents:= objWMI:ExecNotificationQuery("Select * from __InstanceOperationEvent WITHIN "+intInterval+ ; "Where Targetinstance ISA 'CIM_DataFile' And TargetInstance.Drive="+"'"+strdrive+"'"+; "And TargetInstance.Path="+"'"+strFolder+"'" ) do while .t. if inkey(2)==27 exit endif BEGIN SEQUENCE WITH {| oErr | Break( oErr ) } objEvent:= colEvents:NextEvent(2000) Recover USING oErr * ? oErr:subCode , oErr:operation ,oErr:osCode if "TIMED OUT" $ upper(oErr:description) .or. "0X80043001" $ upper(oErr:description) loop else Return endif End SEQUENCE objTargetInst:= objEvent:TargetInstance For Each elem In objEvent:TargetInstance:Properties_ ? elem:name,elem:value Next enddo return FUNC WMIService( cComp ) Local oWmi, oItem LOCAL oErrSave := ERRORBLOCK( { | objErr | BREAK( objErr ) } ) LOCAL oErr Local oLocator LOCAL cName := '' LOCAl lLocahost := .f. LOCAL cStr := '' hb_default(@cComp,".") oLocator := CreateObject( "wbemScripting.SwbemLocator" ) oWMI := oLocator:ConnectServer(cComp,'root\CIMV2') errorblock(oErrSave) RETURN oWmi [/pre2]

Dima: Dima пишет: local strFolder:= "\\POCKET\\skans\\" Вот тут двойные "палки" ставить обязательно иначе запрос Select может послать лесом... И по ходу вопрос а как преобразовать \POCKET\skans\ в \\POCKET\\skans\\ стандартно и без гимора ? Просто добавив лишнюю палочку.. Проехали hb_StrReplace("\Pocket\Scans\","\",{"\\"})

Dima: Dima пишет: For Each elem In objEvent:TargetInstance:Properties_ ? elem:name,elem:value Next Этот бесполезный кусок кода можно выбросить и вместо него использовать этот [pre2] OpathClass:=objEvent:Path_:Class if OpathClass=="__InstanceCreationEvent" devout(objTargetInst:name,"gr+/n") ? elseif OpathClass=="__InstanceDeletionEvent" devout(objTargetInst:name,"r+/n") ? elseif OpathClass=="__InstanceModificationEvent" devout(objTargetInst:name,"bg+/n") ? endif [/pre2] Осталось понять как ловить эту же инфу из субдиректорий....

Sergy: IMHO, оставлять после обработки пришедшие файлы там, где они и были - тупиковая идея. Чем больше файлов, тем больше тормозов, тем более, если их такое количество. Я-бы создал такую систему: 1) Scans\Watch - сюда прилетают документы на разбор, пусть со своей структурой директориев 2) Scans\Stored - сюда твоя система перемещает документы после их обработки. Возможно с изменением структуры, например Scans\Stored\YYMMDD\... - чтобы автоматом удалять старый и никому не нужный хлам 3) Scans\Error - документы, при обработке которых возникла ошибка В нормальной рабочей ситуации 1 и 3 папки должны быть пустыми. А разбором второй папки нужно заниматься раз в неделю/месяц для подчистки мусора.

Dima: Sergy Ты конечно прав. Но решил я пойти более простым путем и просто слегка модернизируем программу на планшете и она будет кидать в ту папку в которую укажу а там имена папок это даты. А сейчас планшет любой документ даже древний кидает в папку с текущей датой , поэтому и приходилось сканировать все папки на предмет нахождения нужного скана (если он не найден в папке с нужной датой) а так буду сканировать всего одну папку а файлов там пшик от 1 до 50

SergKis: Dima пишет Но решил я пойти более простым путем и просто слегка модернизируем программу на планшете и она будет кидать в ту папку в которую укажу а там имена папок это даты. Не уверен, что это правильно. У меня куча магазинов с разными каталогами, куда они кидают файлы (я этим не управляю), это в основном xml (у них разные структуры док.) + куча агентов с xls и xlsx (планшеты в основном), причем последние не все читаются версией LibXL, которая есть, т.е. требуется через ole прочитать и преобразовать в старый xls (часто это делают руками, т.к. лицензия excel для этого одна). + ftp, которые сканирую я (причем есть вариант с предварительным просмотром, короче, нужный док или нет) + zip + база firebird с документами. Их объединяет наличие в имени файла формата TimeStamp (с миллисекундами или нет). Суть, все файлы обрабатываются из источников и помещаются в working каталог (в основном проверка КС или 7za -t ...). Программа сканирования каталога принятых файлов (уже в working), лезет внутрь документа (кроме firebird) и распределяет файлы по задачам и обработчикам и уже обработчики проверяют правильность структуры файла (ошибочные возвращают клиенту имя файла док. и вариант первой обнаруженной ошибки, ведя лог ошибочных) и вынимают документы и представляют их для работы\просмотра (реестр, содержимое строки) в тсб. Ответственный за прием, принимает решение, принять док-т в задачу или что то с ним не то (в заказах не хватает на складах номенклатуры, например и надо согласовывать), обрабатывают и т.д. Все обработанные док. из каталогов удаляются, лог обработки ведется, т.е working каталог после сканирования (Directory использую) и обработки всегда пуст. Не забываем проверять захват файлов монопольно, только их обрабатываем. После обработчиков все файлы из working, в задаче, сохраняются в первоначальном виде, как пришли и в реестрах на них, как правило, есть ссылки

Dima: SergKis пишет: Не забываем проверять захват файлов монопольно, только их обрабатываем Это интересно. Как проверяешь ? Лично я проверяю время жизни файла , если более x минут то его можно брать и делать с ним что угодно. Чекаю с помощью FileStats. PS Полагаю через Fopen

SergKis: Dima пишет Полагаю через Fopen Были варианты, но закончились простым [pre2] *-----------------------------------------------------------------------------* FUNCTION IsFileConnect( cFile ) *-----------------------------------------------------------------------------* LOCAL hFile IF ! hb_FileExists( cFile ) ; RETURN .F. ENDIF IF ( hFile := FOpen(cFile, 2) ) > 0 ; FClose( hFile ) ELSE ; RETURN .F. ENDIF RETURN .T. [/pre2] Если не срослось в этот раз, схватится в следующий (timer ставится через ini, default ~5-20 sek). Часто firebird попадает под эту раздачу, он большой (док. с накоплением какой то период) и может идти не fdb, а bak. Это после Directory(), работа по списку

Dima: SergKis пишет: IF ( hFile := FOpen(cFile, 2) ) Кхм я юзаю вместо 2 , 18 Так надежнее мне кажется. SUV еще про это писал

SergKis: Dima пишет Так надежнее мне кажется. Я читал, но сделано бывает давно (18 не ставил, надо тестить ... на веру брать, сам знаешь, PC os разные ...), да и дергаться тут нет смысла, т.к. обработчики с BEGIN SEQUNCE ... Не обработал, файл остался, след. Directory() попытается обработать.

Dima: SergKis пишет: IF ( hFile := FOpen(cFile, 2) ) > 0 похоже надо IF ( hFile := FOpen(cFile, 2) ) >= 0 [pre2] If there is an error in opening a file, a -1 will be returned by the function. Files handles may be in the range of 0 to 65535 [/pre2]

SergKis: Dima пишет похоже надо IF ( hFile := FOpen(cFile, 2) ) >= 0 Значения handle 0, 1, 2 заняты уже, так что достаточно проверки > 0, т.е. (от А. Кресина ф-я cedi_rediron(...)) [pre2] IF hb_FileExists( cPrg ) .and. ! hb_FileExists( cHrb ) // compile prg -> hrb cTmp := hb_memoread(cPrg) IF !Empty(cTmp) nTmp := cedi_rediron( 1, cErr ) nErr := cedi_rediron( 2, cErr ) cBuf := hb_compileFromBuf( cTmp, "harbour", "-n2", "-q", "-w" ) cedi_rediroff( 2, nErr ) cedi_rediroff( 1, nTmp ) cTmp := hb_memoread(cErr) IF Empty( cBuf ) .or. " Warning " $ cTmp .or. "Error " $ cTmp .or. "error " $ cTmp cTmp := cPrg + CRLF + CRLF + cTmp IF lNoMain SET WINDOW MAIN OFF ENDIF AlertStop ( cTmp, Txt("ERROR") + " " + Txt("Compile") ) // "COMPILATION ERROR" IF lNoMain SET WINDOW MAIN ON ENDIF lRet := .F. // compile error ELSE hb_memowrit(cHrb, cBuf) fErase(cErr) ENDIF ENDIF ENDIF [/pre2]

Dima: SergKis пишет: Значения handle 0, 1, 2 заняты уже OK



полная версия страницы