יצירת רשימת קבצים ותקיות בתוך תקיה נבחרת
-
מצאתי פרוייקט ממש מוצלח, שבו תוך 3-4 שניות מקבלים רשימה של כל הקבצים והתקיות שיש בכונן C מה שע''י פונקציות רגילות של Directory.GetDirectories או Directory.GetFiles יכול לקחת כמה דקות ארוכות.
אבל הבעיה היא שהוא תמיד סורק את כל הכונן, וזה לא מתאים כאשר הכונן גדול ואני צריך לסרוק רק איזו תקיה קטנה.
השאלה יש למישהו הצעה איך ליעל את הדברים האלו למקסימום? אולי למישהו יש רעיון לשפץ את הפונקציה המהירה שלא תסרוק את הכל אלא רק את מה שצריך?תודה לכולם ושבת שלום.
Public Sub FindAllFiles(ByVal szDriveLetter As String, fFileFound As FileFound_Delegate, fProgress As Progress_Delegate, fMatch As IsMatch_Delegate) Dim usnRecord As USN_RECORD Dim mft As MFT_ENUM_DATA Dim dwRetBytes As Integer Dim cb As Integer Dim dicFRNLookup As New Dictionary(Of Long, FSNode) Dim bIsFile As Boolean ' This shouldn't be called more than once. If m_Buffer.ToInt32 <> 0 Then Console.WriteLine("invalid buffer") Exit Sub End If ' progress If Not IsNothing(fProgress) Then fProgress.Invoke("Building file list.") ' 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("\"c) ' Open the volume handle m_hCJ = OpenVolume(szDriveLetter) ' Check if the volume handle is valid. If m_hCJ = INVALID_HANDLE_VALUE Then Console.WriteLine("Couldn't open handle to the volume.") Cleanup() Exit Sub End If mft.StartFileReferenceNumber = 0 mft.LowUsn = 0 mft.HighUsn = Long.MaxValue Do If DeviceIoControl(m_hCJ, FSCTL_ENUM_USN_DATA, mft, Marshal.SizeOf(mft), m_Buffer, m_BufferSize, dwRetBytes, IntPtr.Zero) Then cb = dwRetBytes ' Pointer to the first record Dim pUsnRecord As New IntPtr(m_Buffer.ToInt32() + 8) While (dwRetBytes > 8) ' Copy pointer to USN_RECORD structure. usnRecord = Marshal.PtrToStructure(pUsnRecord, usnRecord.GetType) ' The filename within the USN_RECORD. Dim FileName As String = Marshal.PtrToStringUni(New IntPtr(pUsnRecord.ToInt32() + usnRecord.FileNameOffset), usnRecord.FileNameLength / 2) 'If Not FileName.StartsWith("$") Then ' use a delegate to determine if this file even matches our criteria Dim bIsMatch As Boolean = True If Not IsNothing(fMatch) Then fMatch.Invoke(FileName, usnRecord.FileAttributes, bIsMatch) If bIsMatch Then bIsFile = Not usnRecord.FileAttributes.HasFlag(FileAttribute.Directory) dicFRNLookup.Add(usnRecord.FileReferenceNumber, New FSNode(usnRecord.FileReferenceNumber, usnRecord.ParentFileReferenceNumber, FileName, bIsFile)) End If 'End If ' Pointer to the next record in the buffer. pUsnRecord = New IntPtr(pUsnRecord.ToInt32() + usnRecord.RecordLength) dwRetBytes -= usnRecord.RecordLength End While ' The first 8 bytes is always the start of the next USN. mft.StartFileReferenceNumber = Marshal.ReadInt64(m_Buffer, 0) Else Exit Do End If Loop Until cb <= 8 If Not IsNothing(fProgress) Then fProgress.Invoke("Parsing file names.") ' Resolve all paths for Files For Each oFSNode As FSNode In dicFRNLookup.Values.Where(Function(o) o.IsFile) Dim sFullPath As String = oFSNode.FileName Dim oParentFSNode As FSNode = oFSNode While dicFRNLookup.TryGetValue(oParentFSNode.ParentFRN, oParentFSNode) sFullPath = String.Concat(oParentFSNode.FileName, "\", sFullPath) End While sFullPath = String.Concat(szDriveLetter, "\", sFullPath) If Not IsNothing(fFileFound) Then fFileFound.Invoke(sFullPath, 0) Next '// cleanup Cleanup() If Not IsNothing(fProgress) Then fProgress.Invoke("Complete.") End Sub
פורסם במקור בפורום CODE613 ב11/10/2013 10:51 (+03:00)
-
לדעתי הוא קורא את הסקטורים בדיסק קשיח ששיכים לאינדקס של כל הקבצים.
בגלל זה זה כל כך מהר כי הוא עוקף את המנגנון של מערכת הפעלה. וגם לכן אי אפשר לעשות פר תקיה כי אתה חייב לקרוא הכל כדי לדעת איפה נמצא הקבצים של התקיה הספציפית שאתה רוצה. אז מימלא זה אותו עבודה.
פורסם במקור בפורום CODE613 ב11/10/2013 12:16 (+03:00)
-
נכון, אבל זה לא ממש אותו עבודה בכל המקרים כי לפעמים יותר מהר לקרוא את כל שמות הקבצים עם הפונקציה המהירה ולסנן רק מה שאני צריך מאשר ללכת עם הפונקציות Directory.GetDirectories או Directory.GetFiles ולפעמים זה להיפך, השאלה אם יש איזו עצה מבריקה איך אני אדע מראש באיזו דרך לילך? [או אולי להפעיל את שניהם ומי שיגמור ראשון לקחת אותו, ולהפסיק את השני....?]
פורסם במקור בפורום CODE613 ב12/10/2013 21:28 (+03:00)
-
נכון, אבל זה לא ממש אותו עבודה בכל המקרים כי לפעמים יותר מהר לקרוא את כל שמות הקבצים עם הפונקציה המהירה ולסנן רק מה שאני צריך מאשר ללכת עם הפונקציות Directory.GetDirectories או Directory.GetFiles ולפעמים זה להיפך, השאלה אם יש איזו עצה מבריקה איך אני אדע מראש באיזו דרך לילך? [או אולי להפעיל את שניהם ומי שיגמור ראשון לקחת אותו, ולהפסיק את השני....?]
התכוונתי שהקריאה בשיטה שהבאת זה אותו עבודה בין אם זה תקיה ספציפית או הכל.
ולדעתי הפעלה של שניהם לא יהיה טוב כי זה דיסק קשיח אחד והוא קורא לפי תור אז ככה זה ימעיט לך חצי מהביצועים.
פורסם במקור בפורום CODE613 ב13/10/2013 14:39 (+03:00)