vb@rchiv
VB Classic
VB.NET
ADO.NET
VBA
C#
Top-Preis! AP-Access-Tools-CD Volume 1  
 vb@rchiv Quick-Search: Suche startenErweiterte Suche starten   RSS-Feeds  | Newsletter  | Impressum  | vb@rchiv CD Vol.6  | Shop Copyright ©2000-2014
 
zurück
Rubrik: Dateisystem · Dateien - allgemein   |   VB-Versionen: VB2005, VB200808.12.08
Asynchrone FileScan API-Klasse

VB.NET Klasse zur Ermittlung aller Dateien eines Ordners/Unterordners, die mit einem bestimmten Such-Pattern ?bereinstimmen.

Autor:   Roland WutzkeBewertung:     [ Jetzt bewerten ]Views:  5.795 
www.vb-power.netSystem:  Win2k, WinXP, Vista, Win7, Win8 Beispielprojekt auf CD 

Die nachfolgende VB.NET Klasse ermittelt aufgrund des angegebenen SearchPattern alle Dateien eines Ordners und bei Bedarf auch deren Unterordner. 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.

Ein Treffer wird direkt über das Event ScannedFile zurückgegeben und kann in der GUI sofort verarbeitet werden.

Nachfoldend die Klasse "FileScan":

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

Dieser Tipp wurde bereits 5.795 mal aufgerufen.

Voriger Tipp   |   Zufälliger Tipp   |   Nächster Tipp

Über diesen Tipp im Forum diskutieren
Haben Sie Fragen oder Anregungen zu diesem Tipp, können Sie gerne mit anderen darüber in unserem Forum diskutieren.

Neue Diskussion eröffnen

nach obenzurück


Anzeige

Kauftipp Unser Dauerbrenner!Diesen und auch alle anderen Tipps & Tricks finden Sie auch auf unserer aktuellen vb@rchiv  Vol.6
(einschl. Beispielprojekt!)

Ein absolutes Muss - Geballtes Wissen aus mehr als 8 Jahren vb@rchiv!
- nahezu alle Tipps & Tricks und Workshops mit Beispielprojekten
- Symbol-Galerie mit mehr als 3.200 Icons im modernen Look
Weitere Infos - 4 Entwickler-Vollversionen (u.a. sevFTP für .NET), Online-Update-Funktion u.v.m.
 
   

Druckansicht Druckansicht Copyright ©2000-2014 vb@rchiv Dieter Otter
Alle Rechte vorbehalten.

Microsoft, Windows und Visual Basic sind entweder eingetragene Marken oder Marken der Microsoft Corporation in den USA und/oder anderen Ländern. Weitere auf dieser Homepage aufgeführten Produkt- und Firmennamen können geschützte Marken ihrer jeweiligen Inhaber sein.

Diese Seiten wurden optimiert für eine Bildschirmauflösung von mind. 1280x1024 Pixel