目录监视,很急,大家来看看(100分)

  • 主题发起人 主题发起人 zjxxln
  • 开始时间 开始时间
Z

zjxxln

Unregistered / Unconfirmed
GUEST, unregistred user!
我有一个目录,远端机器随时向这个目录写文件,我需要实时监视这个目录,<br>一旦有文件写入,我就将文件读入数据库并转发出去。<br>在2000下好像可以用文件通知函数来完成,但是我现在是在98下,<br>大家有没有好的解决办法?
 
对文件夹的监视,你看看这个例子:<br>http://www.vclxx.org/DELPHI/D32SAMPL/DIRMON.ZIP<br>挺管用的。<br>
 
这个例子在2000下运行很好,但是在98下不行。<br>
 
你参考一下这个帖子呢。<br>http://www.delphibbs.com/delphibbs/dispq.asp?lid=840658
 
我看了这些例子,但是他们都只能用在2000下,<br>98下不能用。
 
win98下可能要用VXD了,自己写太困难。。。。<br>这个地方倒是有:<br>http://www.alfaunits.co.yu/<br>但是要购买,看一下价格<br>Alfa File Monitor <br>Alfa File Monitor DevSource license. Provides components for Delphi and Library for MSVC++ to develop applications with Alfa File Monitor. Price US$499.95 <br>Alfa File Monitor VxdSource license. Provides DevSource license plus source code for the VXD driver. Price US$1999.95 <br>Alfa File Monitor SysSource license. Provides DevSource license plus source code for the SYS driver. Price US$3499.95 <br>Alfa File Monitor MILSource license. Provides DevSource license, VXD source, SYS source code and AFM Service source code. Price US$4,999.95 <br>太黑了!!!
 
看一下这个地方:<br>http://www.torry.net/notification.htm
 
价格实在是高,确实黑。<br>我现在想了个笨办法,我先把待监视的目录e:/1/内的文件全部放在另外一个目录e:/下,<br>然后,定义一个定时器,在定时器中:<br>&nbsp; {String ff;<br>&nbsp; String f;<br>&nbsp; TSearchRec sr;<br>&nbsp; if (FindFirst("e://1//*.*", faReadOnly||faHidden||faSysFile||faDirectory||faArchive , sr) == 0)<br>&nbsp; { f="e://1//"+sr.Name;<br>&nbsp; &nbsp;ff="e://"+sr.Name;<br>&nbsp; &nbsp;MoveFileEx(f.c_str(),ff.c_str(),MOVEFILE_REPLACE_EXISTING);<br>&nbsp; &nbsp;执行我需要的其他操作;<br>&nbsp; }<br>FindClose(sr);<br>}<br>大家有没有比这更好的办法?<br>
 
Delphi的Samples页的TShellChangeNotifier就是用来监视目录中文件操作的。<br>简单到了不用动脑子!!!!
 
to OopsWare:<br>&nbsp; 是d6吧,我现在是d5,好像只可在2000下用。<br>to zw84611:<br>&nbsp; 这个例子我下了,也是只在2000下用。<br>
 
不要这么执著了,不就装一台2000吗,肯定比找答案快[:D]
 
D4也可以的,由 Shell32.dll 导出一份 TLB, 里面就有此控件了。
 
all of ways above only demonstrate how to get the message when a file be copyed into,<br>or delete, eg,<br>TShellChangeNotifier<br>http://www.vclxx.org/DELPHI/D32SAMPL/DIRMON.ZIP<br>but if this file is large, how can we know when the process of copy or <br>move is ended.
 
procedure TForm1.Button1Click(Sender: TObject);<br>var<br>&nbsp; Dir:PChar;<br>&nbsp; re:DWORD;<br>&nbsp; ProHandle:THandle;<br>begin<br>&nbsp; re:=1;<br>&nbsp; Dir:='D:/';<br><br>&nbsp; //FindFirstChangeNotification函数创建一个进程,监视目录的变化<br>&nbsp; ProHandle:=FindFirstChangeNotification(Dir,false,<br>&nbsp; &nbsp; FILE_NOTIFY_CHANGE_FILE_NAME or FILE_NOTIFY_CHANGE_SIZE);<br>&nbsp; //创建不成功<br>&nbsp; if ProHandle=INVALID_HANDLE_VALUE then<br>&nbsp; begin<br>&nbsp; &nbsp; beep;<br>&nbsp; &nbsp; ShowMessage(SysErrorMessage(GetLastError));<br>&nbsp; &nbsp; exit;<br>&nbsp; end;<br><br>&nbsp; //如目录确实发生变化,退出<br>&nbsp; while re&lt;&gt;0 do<br>&nbsp; begin<br>&nbsp; &nbsp; //监视前面进程执行情况,re=0表示前面的进程退出,即目录有变化<br>&nbsp; &nbsp; re:=WaitForSingleObject(ProHandle,100);<br>&nbsp; &nbsp; Application.ProcessMessages();<br>&nbsp; end;<br>&nbsp; ShowMessage('当前目录发生改变');<br><br>&nbsp; //循环监视目录的变化情况<br>&nbsp; while true do<br>&nbsp; begin<br>&nbsp; &nbsp; re:=1;<br>&nbsp; &nbsp; //重新执行前面定义的进程<br>&nbsp; &nbsp; FindNextChangeNotification(ProHandle);<br>&nbsp; &nbsp; while re&lt;&gt;0 do<br>&nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; re:=WaitForSingleObject(ProHandle,100);<br>&nbsp; &nbsp; &nbsp; Application.ProcessMessages();<br>&nbsp; &nbsp; end;<br>&nbsp; &nbsp; ShowMessage('当前目录发生改变');<br>&nbsp; end;<br>end;<br>//上面的程序用到死循环,虽然能够使用,但容易死机,<br>//最好用线程改造一下,你自己动动手
 
一篇文章,望对你有用!<br><br><br>在WIN32下用DELPHI侦测目录变化,可用WIN32提供的文件改变通知API来完成。FindFirstChangeNotification, FindNextChangeNotification,FindCloseChangeNotification。<br>在应用程序中调用这些函数时,产生一个监控这个变化的句柄,可用WAIT函数集来等待这个变化。这样,当监控程序运行时,可以达到监控文件变化的动作。更进一步,可把此程序做成一个状态区图标(TRAY)来完成监控。<br><br>Windows在删除、复制、移动、访问文件时并不发送消息,当然截获不到。要截取这些操作过程的唯一办法就是截获API,这又需要你编写Vxd程序了,杀毒软件都是这样作的。你注意一下杀毒软件一般都带有一个vxd程序。光有vxd还不行,还需截获文件API。还有另外一个办法,就是CIH病毒采用的办法,直接跳到系统零层去操作。具体办法如下:<br>一、SIDT指令( 将中断描述符表寄存器IDTR--64位宽,16~47Bit存有中断描述符表IDT基地址--的内容存入指定地址单元)不是特权指令,就是说我们可以在Ring3下执行该指令,获得IDT的基地址,从而修改IDT,增加一个中断门安置我们的中断服务,一旦Ring3程序中产生此中断,VMM就会调用此中断服务程序,而此中断服务程序就运行在Ring0下了。这一点与在DOS下非常相似。<br><br>二、要实现对系统中所有文件I/O操作的实时监视,还要用到另一种关键技-FileHooking,通过挂接一个处理函数,截获所有与文件I/O操作有关的系 统调用。Windows9x使用32位保护模式可安装文件系统(IFS),由可安装文件系统管理器(IFSManager)协调对文件系统和设备的访问,它接收以Win32API函数调用形式向系统发出的文件I/O请求,再将请求转给文件系统驱动程序FSD,由它调用低级别的IOS系统实现最终访问。每个文件I/OAPI调用都有一个特定的FSD函数与之对应,IFSManager负责完成由API到FSD的参数装配工作,在完成文件I/OAPI函数参数的装配之后转相应FSD执行之前,它会调用一个称为FileSystemApiHookFunction的Hooker函数。通过安装自己的Hooker函数,就可以截获系统内所有对文件I/O的API调用,从而实现实时监控。<br>=========================================<br>procedure TForm1.Button2Click(Sender: TObject);<br>begin<br>&nbsp; {establish a notification for file name changes on the selected directory}<br>&nbsp; NotificationHandle := FindFirstChangeNotification(PChar(DirectoryListBox1.Directory), FALSE,FILE_NOTIFY_CHANGE_FILE_NAME);<br>&nbsp; {if the notification was set up correctly, modify some UI elements...}<br>&nbsp; if (NotificationHandle &lt;&gt; INVALID_HANDLE_VALUE) then<br>&nbsp; begin<br>&nbsp; &nbsp; Button1.Enabled := TRUE;<br>&nbsp; &nbsp; Button2.Enabled := FALSE;<br>&nbsp; end<br>&nbsp; else<br>&nbsp; begin<br>&nbsp; &nbsp; {...otherwise indicate that there was an error}<br>&nbsp; &nbsp; ShowMessage('There was an error setting the notification');<br>&nbsp; &nbsp; Exit;<br>&nbsp; end;<br>end;<br><br>procedure TForm1.Button1Click(Sender: TObject);<br>var<br>&nbsp; dwResult: DWORD; &nbsp; &nbsp; &nbsp; &nbsp; // holds the result of waiting on the notification<br>&nbsp; Waiting: Boolean; &nbsp; &nbsp; &nbsp; &nbsp;// loop control variable<br>begin<br>&nbsp; {setup the loop control for a continuous loop}<br>&nbsp; Waiting := TRUE;<br>&nbsp; {indicate that the application is waiting for the change notification to fire}<br>&nbsp; Button1.Enabled := FALSE;<br>&nbsp; StatusBar1.SimpleText := 'Now waiting for a filename change';<br>&nbsp; Application.ProcessMessages;<br>&nbsp; {enter the loop}<br>&nbsp; while Waiting do<br>&nbsp; begin<br>&nbsp; &nbsp; {at this point, the application is suspended until the notification<br>&nbsp; &nbsp; &nbsp;object is signaled that a filename change has occured in the<br>&nbsp; &nbsp; &nbsp;selected directory (this includes file deletions)}<br>&nbsp; &nbsp; dwResult := WaitForSingleObject(NotificationHandle,INFINITE);<br>&nbsp; &nbsp; if (dwResult = WAIT_OBJECT_0) then<br><br>&nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; {indicate that the notification object was signaled}<br>&nbsp; &nbsp; &nbsp; ShowMessage('The selected directory signaled a filename change');<br><br>&nbsp; &nbsp; &nbsp; {query the user to see if they wish to continue monitoring this<br>&nbsp; &nbsp; &nbsp; &nbsp;directory}<br>&nbsp; &nbsp; &nbsp; if Application.MessageBox('Do you wish to continue monitoring this directory?', 'Continue?', MB_ICONQUESTION or<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MB_YESNO) = IDYES then<br><br>&nbsp; &nbsp; &nbsp; &nbsp; {if the user wishes to continue monitoring the directory, reset<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;the notification object and continue the loop...}<br>&nbsp; &nbsp; &nbsp; &nbsp; FindNextChangeNotification(NotificationHandle)<br>&nbsp; &nbsp; &nbsp; else<br>&nbsp; &nbsp; &nbsp; &nbsp; {...otherwise break out of the loop}<br>&nbsp; &nbsp; &nbsp; &nbsp; Waiting := FALSE;<br>&nbsp; &nbsp; end;<br>&nbsp; end;<br><br>&nbsp; {close the notification object}<br>&nbsp; FindCloseChangeNotification(NotificationHandle);<br><br>&nbsp; {reset UI elements}<br><br>&nbsp; Button1.Enabled := FALSE;<br>&nbsp; Button2.Enabled := TRUE;<br>&nbsp; StatusBar1.SimpleText := '';<br>&nbsp; FileListBox1.Update;<br>end;<br>===========================================<br>下面是一个监视的控件:<br>unit dirnotify;<br><br>interface<br><br>uses<br>&nbsp; Windows, Messages, SysUtils, Classes,<br>&nbsp; Graphics, Controls, Forms, Dialogs;<br><br>type<br>&nbsp; EDirNotificationError = class(Exception);<br><br>&nbsp; TDirNotify = class;<br>&nbsp; TNotifyFilter = (nfFileName, nfDirName, nfAttributes, nfSize, nfLastWrite,<br>&nbsp; &nbsp; nfSecurity);<br>&nbsp; TNotifyFilters = set of TNotifyFilter;<br><br>&nbsp; TNotificationThread = class(TThread)<br>&nbsp; &nbsp; Owner: TDirNotify;<br>&nbsp; &nbsp; procedure Execute; override;<br>&nbsp; &nbsp; procedure DoChange;<br>&nbsp; end;<br><br>&nbsp; TDirNotify = class(TComponent)<br>&nbsp; private<br>&nbsp; &nbsp; FEnabled: Boolean;<br>&nbsp; &nbsp; FOnChange: TNotifyEvent;<br>&nbsp; &nbsp; FNotificationThread: TNotificationThread;<br>&nbsp; &nbsp; FPath: String;<br>&nbsp; &nbsp; FWatchSubTree: Boolean;<br>&nbsp; &nbsp; FFilter: TNotifyFilters;<br><br>&nbsp; &nbsp; procedure SetEnabled( Value: Boolean );<br>&nbsp; &nbsp; procedure SetOnChange( Value: TNotifyEvent );<br>&nbsp; &nbsp; procedure SetPath( Value: String );<br>&nbsp; &nbsp; procedure SetWatchSubTree( Value: Boolean );<br>&nbsp; &nbsp; procedure SetFilter( Value: TNotifyFilters );<br><br>&nbsp; &nbsp; procedure RecreateThread;<br><br>&nbsp; protected<br>&nbsp; &nbsp; procedure Change;<br>&nbsp; &nbsp; procedure Loaded; override;<br><br>&nbsp; public<br>&nbsp; &nbsp; constructor Create(AOwner: TComponent); override;<br>&nbsp; &nbsp; destructor Destroy; override;<br><br>&nbsp; published<br>&nbsp; &nbsp; property Enabled: Boolean read FEnabled write SetEnabled default True;<br>&nbsp; &nbsp; property OnChange: TNotifyEvent read FOnChange write SetOnChange;<br>&nbsp; &nbsp; property Path: String read FPath write SetPath;<br>&nbsp; &nbsp; property WatchSubTree: Boolean read FWatchSubTree write SetWatchSubTree;<br>&nbsp; &nbsp; property Filter: TNotifyFilters read FFilter write SetFilter default [nfFileName, nfDirName, nfAttributes, nfLastWrite, nfSecurity];<br>&nbsp; end;<br><br><br>procedure Register;<br><br>implementation<br><br>const<br>&nbsp; LASTERRORTEXTLENGTH = 500;<br><br>var<br>&nbsp; LastErrorText: array [0..LASTERRORTEXTLENGTH] of char;<br><br><br>function GetLastErrorText: PChar;<br>begin<br>&nbsp; FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM,<br>&nbsp; &nbsp; nil, GetLastError, 0, LastErrorText, LASTERRORTEXTLENGTH, nil );<br>&nbsp; Result := LastErrorText;<br>end;<br><br><br>procedure TNotificationThread.Execute;<br>var<br>&nbsp; h: THandle;<br>&nbsp; nf: Longint;<br>&nbsp; wst: LongBool;<br>begin<br>&nbsp; nf := 0;<br>&nbsp; if (nfFileName in Owner.Filter) then nf := FILE_NOTIFY_CHANGE_FILE_NAME;<br>&nbsp; if (nfDirName in Owner.Filter) then nf := nf or FILE_NOTIFY_CHANGE_DIR_NAME;<br>&nbsp; if (nfAttributes in Owner.Filter) then nf := nf or FILE_NOTIFY_CHANGE_ATTRIBUTES;<br>&nbsp; if (nfSize in Owner.Filter) then nf := nf or FILE_NOTIFY_CHANGE_SIZE;<br>&nbsp; if (nfLastWrite in Owner.Filter) then nf := nf or FILE_NOTIFY_CHANGE_LAST_WRITE;<br>&nbsp; if (nfSecurity in Owner.Filter) then nf := nf or FILE_NOTIFY_CHANGE_SECURITY;<br><br>&nbsp; // yeahh, this one is stupid but Win98 malfunctions in any other value than 0 or 1<br>&nbsp; if Owner.FWatchSubTree then wst := Longbool(1)<br>&nbsp; else wst := Longbool(0);<br><br>&nbsp; h := FindFirstChangeNotification( Pointer(Owner.Path), wst, nf );<br>&nbsp; if (h = INVALID_HANDLE_VALUE) then<br>&nbsp; &nbsp; raise EDirNotificationError.Create( GetLastErrorText );<br><br>&nbsp; repeat<br>&nbsp; &nbsp; if (WaitForSingleObject( h, 1000 ) = WAIT_OBJECT_0) then<br>&nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; Synchronize(DoChange);<br><br>&nbsp; &nbsp; &nbsp; if not FindNextChangeNotification( h ) then<br>&nbsp; &nbsp; &nbsp; &nbsp; raise EDirNotificationError.Create( GetLastErrorText );<br>&nbsp; &nbsp; end;<br>&nbsp; until Terminated;<br>end;<br><br><br>procedure TNotificationThread.DoChange;<br>begin<br>&nbsp; &nbsp;Owner.Change;<br>end;<br><br><br>constructor TDirNotify.Create(AOwner: TComponent);<br>begin<br>&nbsp; inherited Create(AOwner);<br><br>&nbsp; FEnabled := True;<br>&nbsp; FFilter := [nfFileName];<br>end;<br><br><br>destructor TDirNotify.Destroy;<br>begin<br>&nbsp; FNotificationThread.Free;<br>&nbsp; inherited Destroy;<br>end;<br><br>procedure TDirNotify.Loaded;<br>begin<br>&nbsp; inherited;<br><br>&nbsp; RecreateThread;<br>end;<br><br><br>procedure TDirNotify.SetEnabled(Value: Boolean);<br>begin<br>&nbsp; if Value &lt;&gt; FEnabled then<br>&nbsp; begin<br>&nbsp; &nbsp; FEnabled := Value;<br><br>&nbsp; &nbsp; RecreateThread;<br>&nbsp; end;<br>end;<br><br><br>procedure TDirNotify.SetPath( Value: String );<br>begin<br>&nbsp; if Value &lt;&gt; FPath then<br>&nbsp; begin<br>&nbsp; &nbsp; FPath := Value;<br>&nbsp; &nbsp; RecreateThread;<br>&nbsp; end;<br>end;<br><br><br>procedure TDirNotify.SetWatchSubTree( Value: Boolean );<br>begin<br>&nbsp; if Value &lt;&gt; FWatchSubTree then<br>&nbsp; begin<br>&nbsp; &nbsp; FWatchSubTree := Value;<br>&nbsp; &nbsp; RecreateThread;<br>&nbsp; end;<br>end;<br><br><br>procedure TDirNotify.SetFilter( Value: TNotifyFilters );<br>begin<br>&nbsp; if Value &lt;&gt; FFilter then<br>&nbsp; begin<br>&nbsp; &nbsp; FFilter := Value;<br>&nbsp; &nbsp; RecreateThread;<br>&nbsp; end;<br>end;<br><br><br>procedure TDirNotify.SetOnChange(Value: TNotifyEvent);<br>begin<br>&nbsp; &nbsp;FOnChange := Value;<br>end;<br><br><br>procedure TDirNotify.Change;<br>begin<br>&nbsp; &nbsp;if Assigned(FOnChange) then<br>&nbsp; &nbsp; &nbsp; FOnChange(Self);<br>end;<br><br><br>procedure TDirNotify.RecreateThread;<br>begin<br>&nbsp; // destroy thread<br>&nbsp; FNotificationThread.Free;<br>&nbsp; FNotificationThread := nil;<br><br>&nbsp; if FEnabled and not(csDesigning in ComponentState)<br>&nbsp; &nbsp; and not(csLoading in ComponentState) and (FPath &lt;&gt; '') then<br>&nbsp; begin<br>&nbsp; &nbsp; // create thread<br>&nbsp; &nbsp; FNotificationThread := TNotificationThread.Create(True);<br>&nbsp; &nbsp; FNotificationThread.Owner := self;<br>&nbsp; &nbsp; FNotificationThread.Resume;<br>&nbsp; end;<br>end;<br><br><br>procedure Register;<br>begin<br>&nbsp; &nbsp;RegisterComponents('System', [TDirNotify]);<br>end;<br><br>end.<br>
 
多人接受答案了。
 
后退
顶部