VB-Power.net

Asynchrone FileScan API-Klasse


Klassenmodule
Erstellt am 25 Jan 2009
VB.Net Code-Snippets, Klassen und mehr... >> Klassenmodule

Die nachfolgende VB.Net Klasse ermittelt aufgrund des angegebenen SearchPattern alle Dateien eines Ordners und bei Bedarf auch deren Unter-Ordner. Dabei wird eine gefundene Übereinstimmung (Treffer) über ein Event direkt an die aufrufende Form zurückgegeben. Die Klasse wird als Thread mit dem BackgroundWorker ausgeführt, so dass die Anwendung nicht einfriert. Der BackgroundWorker bietet weiterhin den Vorteil, dass wir uns nicht um threadübergreifende Zugriffe auf die GUI kümmern müssen – wir also nicht mit Invoke arbeiten müssen, so dass auch der weniger erfahrene VB-Programmierer problemlos mit der Klasse arbeiten kann.

 

Durch die Verwendung der „FindFirstFile“ und „FindNextFile“ APIs erhalten wir den Vorteil, dass ein Treffer direkt zurückgegeben werden kann. Dies ist mit den DotNet Bordmitteln so nicht möglich, da uns System.IO.Directory.GetFiles erst ein String-Array zurückliefert, wenn die Suche abgeschlossen ist – was bei tiefen Verzeichnisbäumen schon mal ein bisschen dauern kann.

Imports System
Imports System.IO
Imports System.Runtime
Imports System.Runtime.InteropServices
 
''' <summary>
''' Asynchrone FileScan API-Klasse
''' </summary>
''' <remarks>
''' Die Klasse ermittelt aufgrund des angegebenen SearchPattern alle Dateien
''' eines Folders und bei Bedarf auch deren Sub-Folder. Dabei wird eine
''' gefundene Übereinstimmung (Treffer) über ein Event direkt an die aufrufende
''' Form zurückgegeben. Die Klasse wird als Thread mit dem BackgroundWorker
''' ausgeführt, so dass die Anwendung nicht "einfriert".
''' 
''' http://www.vb-power.net
''' </remarks>
Public Class FileScan

  Private WithEvents worker As New System.ComponentModel.BackgroundWorker
 
  Private m_StartFolder As String = String.Empty
  Private m_SearchPattern As String = "*.*"
  Private m_SearchOption As SearchOption = SearchOption.AllDirectories
  Private m_FileScanRunning As Boolean = False
 
  Public Event BeginScan(ByVal sender As Object, ByVal e As EventArgs)
  Public Event EndScan(ByVal sender As Object, ByVal e As EventArgs)
  Public Event ScannedFile(ByVal sender As Object, ByVal e As FileScanEventArgs)
  Public Event CurrentFolder(ByVal sender As Object, ByVal e As FileScanEventArgs)

#Region "API Deklaration"
  Private Declare Auto Function FindFirstFile Lib "kernel32.dll" ( _
    ByVal lpFileName As String, _
    ByRef lpFindData As WIN32_FIND_DATA) As IntPtr
 
  Private Declare Auto Function FindNextFile Lib "kernel32.dll" ( _
    ByVal hFindFile As IntPtr, _
    ByRef lpFindData As WIN32_FIND_DATA) As IntPtr
 
  Private Declare Function FindClose Lib "kernel32.dll" ( _
    ByVal hFindFile As IntPtr) As Boolean
 
  <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _
  Private Structure WIN32_FIND_DATA
    Public sfileAttributes As Int32
    Public creationTime_lowDateTime As Int32
    Public creationTime_highDateTime As Int32
    Public lastAccessTime_lowDateTime As Int32
    Public lastAccessTime_highDateTime As Int32
    Public lastWriteTime_lowDateTime As Int32
    Public lastWriteTime_highDateTime As Int32
    Public nFileSizeHigh As Int32
    Public nFileSizeLow As Int32
    Public dwReserved0 As Int32
    Public dwReserved1 As Int32
    <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=MAX_PATH)> _
    Public fileName As String
    <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=14)> _
    Public alternateFileName As String
  End Structure
 
  Private Const MAX_PATH As Integer = 260
  Private Const INVALID_HANDLE_VALUE As Integer = -1
  Private Const FILE_ATTRIBUTE_DIRECTORY As Integer = &H10
#End Region

#Region "SearchParams"
  ''' <summary>
  ''' Interne Struktur zur Übergabe an den BGW
  ''' </summary>
  Private Structure SearchParams
    Dim StartFolder As String
    Dim SearchPattern As String
    Dim SearchOption As SearchOption
  End Structure
#End Region

#Region "FileScanEventArgs"
  ''' <summary>
  ''' Diese Event-Arg Klasse beinhaltet je ein Treffer und wird
  ''' mit den Events "ScannedFile" und "CurrentFolder" übergeben.
  ''' </summary>
  Public Class FileScanEventArgs
    Inherits EventArgs
 
    Public FileName As String = String.Empty
    Public FolderName As String = String.Empty
 
    Public Sub New(ByVal sFileName As String, ByVal sFolderName As String)
      Me.FileName = sFileName
      Me.FolderName = sFolderName
    End Sub
  End Class
#End Region

#Region "Properties"
  ''' <summary>
  ''' Gibt den Zustand des FileScans an
  ''' </summary>
  ''' <value>Boolean</value>
  ''' <returns>True, wenn der Scan läuft. Anderenfalls False.</returns>
  Public ReadOnly Property FileScanRunning() As Boolean
    Get
      Return m_FileScanRunning
    End Get
  End Property

  ''' <summary>
  ''' SearchPattern für den FileScan (Default: *.*)
  ''' </summary>
  ''' <value>Ein gültiger String mit dem Pattern</value>
  Public Property SearchPattern() As String
    Get
      Return m_SearchPattern
    End Get
    Set(ByVal value As String)
      If String.IsNullOrEmpty(value) Then
        Throw New Exception("SearchPattern darf nicht NULL sein")
      Else
        m_SearchPattern = value
      End If
    End Set
  End Property

  ''' <summary>
  ''' SearchOption für den FileScan (Default: AllDirectories)
  ''' </summary>
  Public Property SearchOption() As SearchOption
    Get
      Return m_SearchOption
    End Get
    Set(ByVal value As SearchOption)
      m_SearchOption = value
    End Set
  End Property

  ''' <summary>
  ''' Bestimmt den Start-Folder für den FileScan
  ''' </summary>
  ''' <value>Ein gültiger String mit dem StartFolder</value>
  ''' <remarks>UNC-Pfade sind zulässig</remarks>
  Public Property StartFolder() As String
    Get
      Return m_StartFolder
    End Get
    Set(ByVal value As String)
      If String.IsNullOrEmpty(value) Then
        Throw New Exception("StartFolder darf nicht NULL sein")
      Else
        m_StartFolder = value
        If Not m_StartFolder.EndsWith("\") Then
          m_StartFolder &= "\"
        End If
      End If
    End Set
  End Property
#End Region

#Region "Methoden"
 
  ''' <summary>
  ''' Startet den asynchronen Scan Vorgang
  ''' </summary>
  Public Sub StartScan()
    Dim p As New SearchParams
    p.StartFolder = m_StartFolder
    p.SearchPattern = m_SearchPattern
    p.SearchOption = m_SearchOption
 
    RaiseEvent BeginScan(Me, New EventArgs)
 
    Me.worker.WorkerReportsProgress = True
    Me.worker.WorkerSupportsCancellation = True
    Me.worker.RunWorkerAsync(p)
    m_FileScanRunning = True
  End Sub

  ''' <summary>
  ''' Beendet vorzeitig den Scan Vorgang
  ''' </summary>
  Public Sub CancelScan()
    If Me.worker.IsBusy Then
      Me.worker.CancelAsync()
    End If
  End Sub

  ''' <summary>
  ''' Interner BGW DoWork Event
  ''' </summary>
  Private Sub worker_DoWork(ByVal sender As Object, _
    ByVal e As System.ComponentModel.DoWorkEventArgs) _
    Handles worker.DoWork
 
    Dim p As SearchParams = DirectCast(e.Argument, SearchParams)
 
    Try
      Me.FindAllFiles(p.StartFolder, p.SearchPattern, p.SearchOption)
    Catch ex As Exception
      Throw New Exception(ex.Message)
    End Try
  End Sub

  ''' <summary>
  ''' Interner BGW ProgressChanged Event
  ''' </summary>
  Private Sub worker_ProgressChanged(ByVal sender As Object, _
    ByVal e As System.ComponentModel.ProgressChangedEventArgs) _
    Handles worker.ProgressChanged
 
    Select Case e.ProgressPercentage
      Case 0
        RaiseEvent ScannedFile(Me, New FileScanEventArgs( _
          e.UserState(0).ToString, e.UserState(1).ToString))
      Case 1
        RaiseEvent CurrentFolder(Me, New FileScanEventArgs( _
          e.UserState(0).ToString, e.UserState(1).ToString))
    End Select
  End Sub

  ''' <summary>
  ''' Interner BGW RunWorkerCompleted Event
  ''' </summary>
  Private Sub worker_RunWorkerCompleted(ByVal sender As Object, _
    ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) _
    Handles worker.RunWorkerCompleted
 
    m_FileScanRunning = False
    RaiseEvent EndScan(Me, New EventArgs)
  End Sub

  ''' <summary>
  ''' Interne API-FileFind Methode
  ''' </summary>
  Private Sub FindAllFiles(ByVal sStartFolder As String, _
    ByVal sSearchPattern As String, ByVal iSearchOption As SearchOption)
 
    Dim w32data As New WIN32_FIND_DATA
    Dim Handle As Integer = FindFirstFile(Path.Combine( _
      sStartFolder, "*.*"), w32data)
 
    If Handle <> INVALID_HANDLE_VALUE Then
      Do
        If Me.worker.CancellationPending Then
          FindClose(Handle)
          Return
        End If
 
        If (w32data.sfileAttributes And FILE_ATTRIBUTE_DIRECTORY) = _
          FILE_ATTRIBUTE_DIRECTORY AndAlso _
          iSearchOption = IO.SearchOption.AllDirectories Then
 
          If w32data.fileName <> "." And w32data.fileName <> ".." Then
            Me.worker.ReportProgress(1, New Object() {String.Empty, _
              sStartFolder})
            FindAllFiles(Path.Combine(sStartFolder, w32data.fileName), _
              sSearchPattern, iSearchOption)
          End If
        Else
          If w32data.fileName <> "." And w32data.fileName <> ".." Then
            If w32data.fileName Like sSearchPattern Then
              Me.worker.ReportProgress(0, New Object() {Path.Combine( _
                sStartFolder, w32data.fileName), sStartFolder})
            End If
          End If
        End If
      Loop Until FindNextFile(Handle, w32data) = False
 
      FindClose(Handle)
    End If
  End Sub
#End Region

End Class

Anwendungsbeispiel:

Platzieren Sie auf die Form ein ListBox-Control, ein Button mit der Beschriftung "Start" und ein Label-Control für die Ausgabe des aktuellen Ordners.

Public Class Form1
  ' FileScan-Klasse mit Events
  Private WithEvents MyFileScan As New FileScan
 
  ' Anzahl Treffer
  Private FoundMatches As Integer

  ''' <summary>
  ''' Start/Stop des FileScans
  ''' </summary>
  Private Sub Button1_Click(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles Button1.Click
 
    Select Case MyFileScan.FileScanRunning
      Case False
        Try
          With MyFileScan
            ' Eigenschaften für den FileScan festlegen
            .StartFolder = "D:\"
            .SearchPattern = "*.txt"
            .SearchOption = IO.SearchOption.AllDirectories
 
            ' Scan starten
            .StartScan()
          End With
        Catch ex As Exception
          ' Fehler
          MsgBox("Fehler!" & vbCrLf & ex.Message, MsgBoxStyle.Exclamation)
        End Try
 
      Case True
        ' Filescan beenden
        MyFileScan.CancelScan()
    End Select
  End Sub

  ''' <summary>
  ''' Neuer Scan-Vorgang
  ''' </summary>
  Private Sub MyFileScan_BeginScan(ByVal sender As Object, _
    ByVal e As System.EventArgs) Handles MyFileScan.BeginScan
 
    FoundMatches = 0
    ListBox1.Items.Clear()
    Button1.Text = "Stop"
  End Sub

  ''' <summary>
  '''  Ausgabe des aktuellen Ordners
  ''' </summary>
  Private Sub MyFileScan_CurrentFolder(ByVal sender As Object, _
    ByVal e As FileScan.FileScanEventArgs) Handles MyFileScan.CurrentFolder
 
    Label1.Text = e.FolderName
  End Sub

  ''' <summary>
  '''  Scan-Vorgang beendet
  ''' </summary>
  Private Sub MyFileScan_EndScan(ByVal sender As Object, _
    ByVal e As System.EventArgs) Handles MyFileScan.EndScan
 
    Button1.Text = "Start"
    MsgBox("Anzahl gefundener Übereinstimmungen: " & FoundMatches, _
      MsgBoxStyle.Information)
  End Sub

  ''' <summary>
  ''' Ergebnis der Liste hinzufügen
  ''' </summary>
  Private Sub MyFileScan_ScannedFile(ByVal sender As Object, _
    ByVal e As FileScan.FileScanEventArgs) Handles MyFileScan.ScannedFile
 
    ListBox1.Items.Insert(0, e.FileName)
    FoundMatches += 1
  End Sub

End Class

Letzte Änderung: 13 Feb 2009 at 22:49

Zurück
TOP Download !!!

DataGridView Control Extender

Erweitern Sie Ihr DataGridView mit 16 zusätzlichen Spaltentypen.


Weiterlesen...


TOP 5 Downloads
WpfOSMMap7084
Explorer TreeView mit VB.Net - Beispielprojekt5049
DataGridView Control Extender incl. VB2008 Demoprojekt4806
MCIFramework.dll3408
DataGridView Control Extender incl. VB2005 Demoprojekt3085
Powered by:

Powered By VB-Power.net