本文只针对NTFS格式化的磁盘文件快速检索,速度不是非常快,是让你震惊。
一般用文件遍历的方法检索一个50G的文件夹需要几十分钟甚至一个小时的时间,而用本方法只需几秒。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250 |
using
System; using
System.Collections.Generic; using
System.Linq; using
System.Text; using
System.Runtime.InteropServices; using
Microsoft.VisualBasic; public
class MFTScanner { private
static IntPtr INVALID_HANDLE_VALUE = new
IntPtr(-1); private
const uint GENERIC_READ = 0x80000000; private
const int FILE_SHARE_READ = 0x1; private
const int FILE_SHARE_WRITE = 0x2; private
const int OPEN_EXISTING = 3; private
const int FILE_READ_ATTRIBUTES = 0x80; private
const int FILE_NAME_IINFORMATION = 9; private
const int FILE_FLAG_BACKUP_SEMANTICS = 0x2000000; private
const int FILE_OPEN_FOR_BACKUP_INTENT = 0x4000; private
const int FILE_OPEN_BY_FILE_ID = 0x2000; private
const int FILE_OPEN = 0x1; private
const int OBJ_CASE_INSENSITIVE = 0x40; private
const int FSCTL_ENUM_USN_DATA = 0x900b3; [StructLayout(LayoutKind.Sequential)] private
struct MFT_ENUM_DATA { public
long StartFileReferenceNumber; public
long LowUsn; public
long HighUsn; } [StructLayout(LayoutKind.Sequential)] private
struct USN_RECORD { public
int RecordLength; public
short MajorVersion; public
short MinorVersion; public
long FileReferenceNumber; public
long ParentFileReferenceNumber; public
long Usn; public
long TimeStamp; public
int Reason; public
int SourceInfo; public
int SecurityId; public
FileAttribute FileAttributes; public
short FileNameLength; public
short FileNameOffset; } [StructLayout(LayoutKind.Sequential)] private
struct IO_STATUS_BLOCK { public
int Status; public
int Information; } [StructLayout(LayoutKind.Sequential)] private
struct UNICODE_STRING { public
short Length; public
short MaximumLength; public
IntPtr Buffer; } [StructLayout(LayoutKind.Sequential)] private
struct OBJECT_ATTRIBUTES { public
int Length; public
IntPtr RootDirectory; public
IntPtr ObjectName; public
int Attributes; public
int SecurityDescriptor; public
int SecurityQualityOfService; } //// MFT_ENUM_DATA [DllImport( "kernel32.dll" , ExactSpelling = true , SetLastError = true , CharSet = CharSet.Auto)] private
static extern bool DeviceIoControl(IntPtr hDevice, int
dwIoControlCode, ref
MFT_ENUM_DATA lpInBuffer, int
nInBufferSize, IntPtr lpOutBuffer, int
nOutBufferSize, ref
int lpBytesReturned, IntPtr lpOverlapped); [DllImport( "kernel32.dll" , SetLastError = true , CharSet = CharSet.Auto)] private
static extern IntPtr CreateFile( string
lpFileName, uint
dwDesiredAccess, int
dwShareMode, IntPtr lpSecurityAttributes, int
dwCreationDisposition, int
dwFlagsAndAttributes, IntPtr hTemplateFile); [DllImport( "kernel32.dll" , ExactSpelling = true , SetLastError = true , CharSet = CharSet.Auto)] private
static extern Int32 CloseHandle(IntPtr lpObject); [DllImport( "ntdll.dll" , ExactSpelling = true , SetLastError = true , CharSet = CharSet.Auto)] private
static extern int NtCreateFile( ref
IntPtr FileHandle, int
DesiredAccess, ref
OBJECT_ATTRIBUTES ObjectAttributes, ref
IO_STATUS_BLOCK IoStatusBlock, int
AllocationSize, int
FileAttribs, int
SharedAccess, int
CreationDisposition, int
CreateOptions, int
EaBuffer, int
EaLength); [DllImport( "ntdll.dll" , ExactSpelling = true , SetLastError = true , CharSet = CharSet.Auto)] private
static extern int NtQueryInformationFile(IntPtr FileHandle, ref
IO_STATUS_BLOCK IoStatusBlock, IntPtr FileInformation, int
Length, int
FileInformationClass); private
IntPtr m_hCJ; private
IntPtr m_Buffer; private
int m_BufferSize; private
string m_DriveLetter; private
class FSNode { public
long FRN; public
long ParentFRN; public
string FileName; public
bool IsFile; public
FSNode( long
lFRN, long
lParentFSN, string
sFileName, bool
bIsFile) { FRN = lFRN; ParentFRN = lParentFSN; FileName = sFileName; IsFile = bIsFile; } } private
IntPtr OpenVolume( string
szDriveLetter) { IntPtr hCJ = default (IntPtr); //// volume handle m_DriveLetter = szDriveLetter; hCJ = CreateFile( "\\\\.\\"
+ szDriveLetter, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero); return
hCJ; } private
void Cleanup() { if
(m_hCJ != IntPtr.Zero) { // Close the volume handle. CloseHandle(m_hCJ); m_hCJ = INVALID_HANDLE_VALUE; } if
(m_Buffer != IntPtr.Zero) { // Free the allocated memory Marshal.FreeHGlobal(m_Buffer); m_Buffer = IntPtr.Zero; } } public
IEnumerable<String> EnumerateFiles( string
szDriveLetter) { try { var
usnRecord = default (USN_RECORD); var
mft = default (MFT_ENUM_DATA); var
dwRetBytes = 0; var
cb = 0; var
dicFRNLookup = new
Dictionary< long , FSNode>(); var
bIsFile = false ; // This shouldn‘t be called more than once. if
(m_Buffer.ToInt32() != 0) { throw
new Exception( "invalid buffer" ); } // Assign buffer size m_BufferSize = 65536; //64KB // Allocate a buffer to use for reading records. m_Buffer = Marshal.AllocHGlobal(m_BufferSize); // correct path szDriveLetter = szDriveLetter.TrimEnd( ‘\\‘ ); // Open the volume handle m_hCJ = OpenVolume(szDriveLetter); // Check if the volume handle is valid. if
(m_hCJ == INVALID_HANDLE_VALUE) { throw
new Exception( "Couldn‘t open handle to the volume." ); } mft.StartFileReferenceNumber = 0; mft.LowUsn = 0; mft.HighUsn = long .MaxValue; do { if
(DeviceIoControl(m_hCJ, FSCTL_ENUM_USN_DATA, ref
mft, Marshal.SizeOf(mft), m_Buffer, m_BufferSize, ref
dwRetBytes, IntPtr.Zero)) { cb = dwRetBytes; // Pointer to the first record IntPtr pUsnRecord = new
IntPtr(m_Buffer.ToInt32() + 8); while
((dwRetBytes > 8)) { // Copy pointer to USN_RECORD structure. usnRecord = (USN_RECORD)Marshal.PtrToStructure(pUsnRecord, usnRecord.GetType()); // The filename within the USN_RECORD. string
FileName = Marshal.PtrToStringUni( new
IntPtr(pUsnRecord.ToInt32() + usnRecord.FileNameOffset), usnRecord.FileNameLength / 2); bIsFile = !usnRecord.FileAttributes.HasFlag(FileAttribute.Directory); dicFRNLookup.Add(usnRecord.FileReferenceNumber, new
FSNode(usnRecord.FileReferenceNumber, usnRecord.ParentFileReferenceNumber, FileName, bIsFile)); // Pointer to the next record in the buffer. pUsnRecord = new
IntPtr(pUsnRecord.ToInt32() + usnRecord.RecordLength); dwRetBytes -= usnRecord.RecordLength; } // The first 8 bytes is always the start of the next USN. mft.StartFileReferenceNumber = Marshal.ReadInt64(m_Buffer, 0); } else { break ; // TODO: might not be correct. Was : Exit Do } } while
(!(cb <= 8)); // Resolve all paths for Files foreach
(FSNode oFSNode in
dicFRNLookup.Values.Where(o => o.IsFile)) { string
sFullPath = oFSNode.FileName; FSNode oParentFSNode = oFSNode; while
(dicFRNLookup.TryGetValue(oParentFSNode.ParentFRN, out
oParentFSNode)) { sFullPath = string .Concat(oParentFSNode.FileName, "\\" , sFullPath); } sFullPath = string .Concat(szDriveLetter, "\\" , sFullPath); yield
return sFullPath; } } finally { //// cleanup Cleanup(); } } } |
调用方法:
using
System; using
System.Collections.Generic; using
System.Linq; using
System.Text; using
System.IO; using
System.Diagnostics; namespace
ConsoleApplication28 { class
Program { static
void Main( string [] args) { var
sw = Stopwatch.StartNew(); var
files = EnumerateFiles( "f:" ).ToArray(); var
elapsed = sw.ElapsedMilliseconds.ToString(); Console.WriteLine( string .Format( "Found {0} files, elapsed {1} ms" , files.Length, elapsed)); } } } |
方法只能传磁盘名
原文:http://www.cnblogs.com/tuyile006/p/3578856.html