@@ -13,9 +13,11 @@ internal sealed class PollingDirectoryWatcher : IDirectoryWatcher
13
13
private readonly DirectoryInfo _watchedDirectory ;
14
14
private readonly bool _includeSubdirectories ;
15
15
16
- private Dictionary < string , FileMeta > _knownFiles = new ( PathUtilities . OSSpecificPathComparer ) ;
17
- private Dictionary < string , FileMeta > _tempDictionary = new ( PathUtilities . OSSpecificPathComparer ) ;
18
- private readonly Dictionary < string , ChangeKind > _changes = new ( PathUtilities . OSSpecificPathComparer ) ;
16
+ private Dictionary < string , DateTime > _currentSnapshot = new ( PathUtilities . OSSpecificPathComparer ) ;
17
+
18
+ // The following are sets that are used to calculate new snapshot and cleared on eached use (pooled):
19
+ private Dictionary < string , DateTime > _snapshotBuilder = new ( PathUtilities . OSSpecificPathComparer ) ;
20
+ private readonly Dictionary < string , ChangeKind > _changesBuilder = new ( PathUtilities . OSSpecificPathComparer ) ;
19
21
20
22
private Thread _pollingThread ;
21
23
private bool _raiseEvents ;
@@ -42,7 +44,7 @@ public PollingDirectoryWatcher(string watchedDirectory, bool includeSubdirectori
42
44
Name = nameof ( PollingDirectoryWatcher )
43
45
} ;
44
46
45
- CreateKnownFilesSnapshot ( ) ;
47
+ CaptureInitialSnapshot ( ) ;
46
48
47
49
_pollingThread . Start ( ) ;
48
50
}
@@ -91,67 +93,53 @@ private void PollingLoop()
91
93
stopwatch . Stop ( ) ;
92
94
}
93
95
94
- private void CreateKnownFilesSnapshot ( )
96
+ private void CaptureInitialSnapshot ( )
95
97
{
96
- _knownFiles . Clear ( ) ;
98
+ Debug . Assert ( _currentSnapshot . Count == 0 ) ;
97
99
98
- ForeachEntityInDirectory ( _watchedDirectory , fileInfo =>
100
+ ForeachEntityInDirectory ( _watchedDirectory , ( filePath , writeTime ) =>
99
101
{
100
- _knownFiles . Add ( fileInfo . FullName , new FileMeta ( fileInfo , foundAgain : false ) ) ;
102
+ _currentSnapshot . Add ( filePath , writeTime ) ;
101
103
} ) ;
102
104
}
103
105
104
106
private void CheckForChangedFiles ( )
105
107
{
106
- _changes . Clear ( ) ;
108
+ Debug . Assert ( _changesBuilder . Count == 0 ) ;
109
+ Debug . Assert ( _snapshotBuilder . Count == 0 ) ;
107
110
108
- ForeachEntityInDirectory ( _watchedDirectory , fileInfo =>
111
+ ForeachEntityInDirectory ( _watchedDirectory , ( filePath , currentWriteTime ) =>
109
112
{
110
- var fullFilePath = fileInfo . FullName ;
111
-
112
- if ( _knownFiles . TryGetValue ( fullFilePath , out var fileMeta ) )
113
+ if ( ! _currentSnapshot . TryGetValue ( filePath , out var snapshotWriteTime ) )
113
114
{
114
- try
115
- {
116
- if ( fileMeta . FileInfo . LastWriteTime != fileInfo . LastWriteTime )
117
- {
118
- // File changed
119
- _changes . TryAdd ( fullFilePath , ChangeKind . Update ) ;
120
- }
121
-
122
- _knownFiles [ fullFilePath ] = new FileMeta ( fileMeta . FileInfo , foundAgain : true ) ;
123
- }
124
- catch ( FileNotFoundException )
125
- {
126
- _knownFiles [ fullFilePath ] = new FileMeta ( fileMeta . FileInfo , foundAgain : false ) ;
127
- }
115
+ _changesBuilder . TryAdd ( filePath , ChangeKind . Add ) ;
128
116
}
129
- else
117
+ else if ( snapshotWriteTime != currentWriteTime )
130
118
{
131
- // File added
132
- _changes . TryAdd ( fullFilePath , ChangeKind . Add ) ;
119
+ _changesBuilder . TryAdd ( filePath , ChangeKind . Update ) ;
133
120
}
134
121
135
- _tempDictionary . Add ( fileInfo . FullName , new FileMeta ( fileInfo , foundAgain : false ) ) ;
122
+ _snapshotBuilder . Add ( filePath , currentWriteTime ) ;
136
123
} ) ;
137
124
138
- foreach ( var ( fullPath , fileMeta ) in _knownFiles )
125
+ foreach ( var ( filePath , _ ) in _currentSnapshot )
139
126
{
140
- if ( ! fileMeta . FoundAgain )
127
+ if ( ! _snapshotBuilder . ContainsKey ( filePath ) )
141
128
{
142
- // File deleted
143
- _changes . TryAdd ( fullPath , ChangeKind . Delete ) ;
129
+ _changesBuilder . TryAdd ( filePath , ChangeKind . Delete ) ;
144
130
}
145
131
}
146
132
147
- NotifyChanges ( ) ;
133
+ NotifyChanges ( _changesBuilder ) ;
148
134
149
135
// Swap the two dictionaries
150
- ( _tempDictionary , _knownFiles ) = ( _knownFiles , _tempDictionary ) ;
151
- _tempDictionary . Clear ( ) ;
136
+ ( _snapshotBuilder , _currentSnapshot ) = ( _currentSnapshot , _snapshotBuilder ) ;
137
+
138
+ _changesBuilder . Clear ( ) ;
139
+ _snapshotBuilder . Clear ( ) ;
152
140
}
153
141
154
- private void ForeachEntityInDirectory ( DirectoryInfo dirInfo , Action < FileSystemInfo > fileAction )
142
+ private void ForeachEntityInDirectory ( DirectoryInfo dirInfo , Action < string , DateTime > fileAction )
155
143
{
156
144
if ( ! dirInfo . Exists )
157
145
{
@@ -180,14 +168,26 @@ private void ForeachEntityInDirectory(DirectoryInfo dirInfo, Action<FileSystemIn
180
168
}
181
169
else
182
170
{
183
- fileAction ( entity ) ;
171
+ string filePath ;
172
+ DateTime currentWriteTime ;
173
+ try
174
+ {
175
+ filePath = entity . FullName ;
176
+ currentWriteTime = entity . LastWriteTimeUtc ;
177
+ }
178
+ catch ( FileNotFoundException )
179
+ {
180
+ continue ;
181
+ }
182
+
183
+ fileAction ( filePath , currentWriteTime ) ;
184
184
}
185
185
}
186
186
}
187
187
188
- private void NotifyChanges ( )
188
+ private void NotifyChanges ( Dictionary < string , ChangeKind > changes )
189
189
{
190
- foreach ( var ( path , kind ) in _changes )
190
+ foreach ( var ( path , kind ) in changes )
191
191
{
192
192
if ( _disposed || ! _raiseEvents )
193
193
{
@@ -197,11 +197,5 @@ private void NotifyChanges()
197
197
OnFileChange ? . Invoke ( this , new ChangedPath ( path , kind ) ) ;
198
198
}
199
199
}
200
-
201
- private readonly struct FileMeta ( FileSystemInfo fileInfo , bool foundAgain )
202
- {
203
- public readonly FileSystemInfo FileInfo = fileInfo ;
204
- public readonly bool FoundAgain = foundAgain ;
205
- }
206
200
}
207
201
}
0 commit comments