Quick.FileMonitor.pas 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. { ***************************************************************************
  2. Copyright (c) 2015-2021 Kike Pérez
  3. Unit : Quick.FileMonitor
  4. Description : Watch for single file changes
  5. Author : Kike Pérez
  6. Version : 1.2
  7. Created : 11/09/2017
  8. Modified : 10/05/2021
  9. This file is part of QuickLib: https://github.com/exilon/QuickLib
  10. ***************************************************************************
  11. Licensed under the Apache License, Version 2.0 (the "License");
  12. you may not use this file except in compliance with the License.
  13. You may obtain a copy of the License at
  14. http://www.apache.org/licenses/LICENSE-2.0
  15. Unless required by applicable law or agreed to in writing, software
  16. distributed under the License is distributed on an "AS IS" BASIS,
  17. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18. See the License for the specific language governing permissions and
  19. limitations under the License.
  20. *************************************************************************** }
  21. unit Quick.FileMonitor;
  22. interface
  23. {$i QuickLib.inc}
  24. uses
  25. Classes,
  26. {$IFDEF MSWINDOWS}
  27. Windows,
  28. SyncObjs,
  29. {$ELSE}
  30. SyncObjs,
  31. {$ENDIF}
  32. SysUtils,
  33. {$IFDEF FPC}
  34. Quick.Files;
  35. {$ELSE}
  36. System.IOUtils;
  37. {$ENDIF}
  38. type
  39. TMonitorNotify = (mnNone, mnFileCreated, mnFileModified, mnFileDeleted);
  40. TMonitorWatch = set of TMonitorNotify;
  41. TFileChangeNotify = procedure(MonitorNofify : TMonitorNotify) of object;
  42. TFileMonitor = class(TThread)
  43. private
  44. fFileName : string;
  45. fTickEvent : TSimpleEvent;
  46. fInterval : Integer;
  47. fNotifies : TMonitorWatch;
  48. fEnabled : Boolean;
  49. fExists : Boolean;
  50. fModifedDate : TDateTime;
  51. fCurrentMonitorNotify : TMonitorNotify;
  52. fOnChangeNotify : TFileChangeNotify;
  53. fIsThreadStarted : Boolean;
  54. procedure SetEnabled(Status : Boolean);
  55. procedure NotifyEvent;
  56. protected
  57. procedure Execute; override;
  58. public
  59. constructor Create;
  60. destructor Destroy; override;
  61. property FileName : string read fFileName write fFileName;
  62. property Interval : Integer read fInterval write fInterval;
  63. property Notifies : TMonitorWatch read fNotifies write fNotifies;
  64. property OnFileChange : TFileChangeNotify read fOnChangeNotify write fOnChangeNotify;
  65. property Enabled : Boolean read fEnabled write SetEnabled;
  66. end;
  67. TQuickFileMonitor = TFileMonitor;
  68. implementation
  69. constructor TFileMonitor.Create;
  70. begin
  71. inherited Create(True);
  72. fIsThreadStarted := False;
  73. fEnabled := False;
  74. Self.FreeOnTerminate := False;
  75. fInterval := 1000;
  76. fExists := False;
  77. fModifedDate := 0;
  78. fCurrentMonitorNotify := mnNone;
  79. fNotifies := [mnFileCreated,mnFileModified,mnFileDeleted];
  80. {$IFDEF FPC}
  81. fTickEvent := TSimpleEvent.Create;
  82. {$ELSE}
  83. fTickEvent := TSimpleEvent.Create(nil,True,False,'');
  84. {$ENDIF}
  85. end;
  86. destructor TFileMonitor.Destroy;
  87. begin
  88. if not Terminated then Terminate;
  89. if fEnabled then
  90. Self.WaitFor;
  91. fTickEvent.SetEvent;
  92. fTickEvent.Free;
  93. inherited;
  94. end;
  95. procedure TFileMonitor.Execute;
  96. var
  97. LastModifiedDate : TDateTime;
  98. begin
  99. inherited;
  100. while not Terminated do
  101. begin
  102. fCurrentMonitorNotify := mnNone;
  103. if fTickEvent.WaitFor(fInterval) = TWaitResult.wrTimeout then
  104. begin
  105. if fEnabled then
  106. begin
  107. if TFile.Exists(fFileName) then
  108. begin
  109. if fExists then
  110. begin
  111. if mnFileModified in fNotifies then
  112. begin
  113. LastModifiedDate := TFile.GetLastWriteTime(fFileName);
  114. if LastModifiedDate > fModifedDate then
  115. begin
  116. fCurrentMonitorNotify := mnFileModified;
  117. fModifedDate := LastModifiedDate;
  118. end;
  119. end;
  120. end
  121. else
  122. begin
  123. if mnFileCreated in fNotifies then fCurrentMonitorNotify := mnFileCreated;
  124. LastModifiedDate := TFile.GetLastWriteTime(fFileName);
  125. fModifedDate := LastModifiedDate;
  126. end;
  127. fExists := True;
  128. end
  129. else
  130. begin
  131. //check if file deleted
  132. if mnFileDeleted in fNotifies then
  133. begin
  134. if fExists then
  135. begin
  136. fExists := False;
  137. fCurrentMonitorNotify := mnFileDeleted;
  138. end;
  139. end;
  140. end;
  141. if fCurrentMonitorNotify <> mnNone then
  142. begin
  143. if IsConsole then NotifyEvent
  144. else Synchronize(NotifyEvent);
  145. end;
  146. end;
  147. end;
  148. end;
  149. end;
  150. procedure TFileMonitor.SetEnabled(Status : Boolean);
  151. begin
  152. if fEnabled <> Status then
  153. begin
  154. if Status then
  155. begin
  156. //gets current values
  157. if TFile.Exists(fFileName) then
  158. begin
  159. fExists := True;
  160. fModifedDate := TFile.GetLastWriteTime(fFileName);
  161. end;
  162. end;
  163. if not fIsThreadStarted then
  164. begin
  165. fIsThreadStarted := True;
  166. if (Status) and {$IFNDEF FPC}(Started = False){$ELSE}(Suspended){$ENDIF} then Start;
  167. end;
  168. fEnabled := Status;
  169. end;
  170. end;
  171. procedure TFileMonitor.NotifyEvent;
  172. begin
  173. if Assigned(fOnChangeNotify) then fOnChangeNotify(fCurrentMonitorNotify);
  174. end;
  175. end.