VB.NET Win32API查找和删除文件(超过260个字符限制)

时间:2015-02-05 07:23:35

标签: .net vb.net function

我正在努力尝试获得一段简单的代码作为一个非常新手的程序员,这就是我想要的:

递归搜索目录(例如D:\ Site_Data),查找具有给定扩展名的所有文件(例如.xrl)并删除它们。

我想使用Win32API的原因是因为我处理埋藏在260多个字母深处的directorys中的文件,并且搜索了高低,无法找到解决方案。 VB.NET是我一直在学习的东西,所以我想坚持下去。

我设法复制了一些代码并进行了调整以删除了一个"单个"使用Kernel32.dll DeleteFile函数的文件,但只有1个文件,它不能接受通配符,这是我得到的:

Imports System
Imports System.Runtime.InteropServices
Imports System.IO


Public Class Form1

Public Property delFile As String


<DllImport("kernel32.dll", CharSet:=CharSet.Unicode, ExactSpelling:=False, SetLastError:=True)> _
Public Shared Function DeleteFile(ByVal path As String) As Boolean
End Function

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

    delFile = "D:\Site_Data\Test.JPG"

    Try
        Dim boolResult As Boolean
        Dim delName As String = "\\?\" + delFile
        boolResult = DeleteFile(delName)
        Debug.WriteLine("Result: " & boolResult.ToString)

    Catch ex As Exception
        Throw ex
    End Try
End Sub
End Class

我明白我要找的是&#34; FindFirstFile&#34;函数但不知道如何编写代码以在VB.NET中实现它。

如果有人能提供帮助,我们将不胜感激。

更新2,工作代码:

Imports System.IO
Imports System.Runtime.InteropServices

Public Class Form1

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim longFolderName As String = "\\?\c:\users\user1\desktop\pics\"
    Dim extensionsToDelete As String = ".jpg"

    Dim filenames As List(Of String) = VeryLongFilenameHandler.GetFilenames(longFolderName)

    For Each filename As String In filenames
        If filename.ToLower.EndsWith(extensionsToDelete) Then
            VeryLongFilenameHandler.DeleteFile(longFolderName + filename)

            Debug.WriteLine("Result: " & longFolderName, filename)

        End If
    Next
End Sub
End Class
Class VeryLongFilenameHandler

<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)>
Structure WIN32_FIND_DATA
    Public dwFileAttributes As UInteger
    Public ftCreationTime As System.Runtime.InteropServices.ComTypes.FILETIME
    Public ftLastAccessTime As System.Runtime.InteropServices.ComTypes.FILETIME
    Public ftLastWriteTime As System.Runtime.InteropServices.ComTypes.FILETIME
    Public nFileSizeHigh As UInteger
    Public nFileSizeLow As UInteger
    Public dwReserved0 As UInteger
    Public dwReserved1 As UInteger
    <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=260)> Public cFileName As String
    <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=14)> Public cAlternateFileName As String
End Structure

<DllImport("kernel32", CharSet:=CharSet.Unicode)>
Public Shared Function FindFirstFile(lpFileName As String, ByRef lpFindFileData As WIN32_FIND_DATA) As IntPtr
End Function

<DllImport("kernel32", CharSet:=CharSet.Unicode)>
Public Shared Function FindNextFile(hFindFile As IntPtr, ByRef lpFindFileData As WIN32_FIND_DATA) As Boolean
End Function

<DllImport("kernel32.dll")>
Public Shared Function FindClose(ByVal hFindFile As IntPtr) As Boolean
End Function

<DllImport("kernel32.dll", CharSet:=CharSet.Unicode, ExactSpelling:=False, SetLastError:=True)>
Public Shared Function DeleteFile(ByVal path As String) As Boolean
End Function


Public Shared Function GetFilenames(folderName As String) As List(Of String)
    Dim filenames As New List(Of String)
    Dim findData As New WIN32_FIND_DATA
    Dim findHandle As New IntPtr
    Dim INVALID_HANDLE_VALUE As New IntPtr(-1)

    ' Add wildcard to foldername to get all files
    folderName += "*"

    findHandle = FindFirstFile(folderName, findData)
    If findHandle <> INVALID_HANDLE_VALUE Then
        Do
            If findData.cFileName <> "." AndAlso findData.cFileName <> ".." AndAlso (findData.dwFileAttributes And FileAttributes.Directory) <> FileAttributes.Directory Then
                filenames.Add(findData.cFileName)
            End If
        Loop While (FindNextFile(findHandle, findData))
        FindClose(findHandle)
    End If

    Return filenames
End Function
End Class

因此,上述方法适用于删除扩展名为.JPG的文件夹内的所有文件,但不会递归执行。

更新3:

再次感谢帮助theduck,非常感谢,我想我几乎在那里,我设法将2个功能分成2个按钮,1个按钮可以列出所有带.jpg的文件,另一个按钮按钮可以列出所有目录,现在它是组合它们的情况,所以我设法用第二个按钮执行下面的操作,但是调试输出不显示它是&#34;假设&#34;删除,这是我到目前为止所得到的,对它应该如何工作有点困惑:

Private Sub Button2_Click(sender As Object, e As EventArgs) Handles     Button2.Click
    Dim longFolderName As String = "\\?\c:\users\Administrator\Desktop\TestDir\"

    Dim foldernames As List(Of String) = VeryLongFilenameHandler.GetFoldernames(longFolderName)

    For Each foldername As String In foldernames
        Dim longFolderName1 As String = (longFolderName + foldername)
        Dim extensionsToDelete As String = ".jpg"

        Dim filenames As List(Of String) = VeryLongFilenameHandler.GetFilenames(longFolderName1)
        MsgBox(longFolderName1)

        For Each filename As String In filenames
            If filename.ToLower.EndsWith(extensionsToDelete) Then
                'VeryLongFilenameHandler.DeleteFile(longFolderName + filename)

                Debug.WriteLine("Deleted: " & longFolderName1 + filename)

            End If
        Next
    Next

End Sub 

MsgBox弹出两个目录,&#34; VeryLongFilenameHandler.GetFoldernames&#34;是您在下面提供的功能调整,仅用于获取目录。我基本上复制了公共共享功能并进行了必要的调整。

更新:工作 好的,现在它可以工作,感谢你,你在示例代码上做的最后一次编辑是完美的,将它链接到一个按钮,我只是将代码从模块内部移动到一个按钮。我当然不会对显而易见的事情视而不见,你基本上为我编写了整个代码块,我非常感谢,很长一段时间我都没有看到这样的帮助。因为我只是一个新手程序员,所以我学得更快的方法是找到工作代码,并分解其工作原理,我比阅读MSDN文章要快得多。

再次感谢你,这里是我的最终代码(由一个Form和一个Button组成)      进口System.IO      Imports System.Runtime.InteropServices      公共类Form1

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles         Button1.Click
    Dim longFolderName As String = "\\?\c:\users\administrator\Desktop\TestDir\"
    Dim extensionToDelete As String = ".jpg"

    RecursiveDelete(longFolderName, extensionToDelete)

End Sub

Sub RecursiveDelete(path As String, extensionToDelete As String)

    If Not path.EndsWith("\") Then path += "\"

    ' Handle all folders below this one
    Dim folders As List(Of String) = VeryLongFilenameHandler.GetFolders(path)
    For Each folder As String In folders
        RecursiveDelete(path + folder, extensionToDelete)
    Next

    ' Delete any applicable files
    Dim filenames As List(Of String) = VeryLongFilenameHandler.GetFilenames(path)

    For Each filename As String In filenames
        If filename.ToLower.EndsWith(extensionToDelete) Then
            VeryLongFilenameHandler.DeleteFile(path + filename)
        End If
    Next

End Sub



End Class

Class VeryLongFilenameHandler

<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)>
Structure WIN32_FIND_DATA
    Public dwFileAttributes As UInteger
    Public ftCreationTime As System.Runtime.InteropServices.ComTypes.FILETIME
    Public ftLastAccessTime As System.Runtime.InteropServices.ComTypes.FILETIME
    Public ftLastWriteTime As System.Runtime.InteropServices.ComTypes.FILETIME
    Public nFileSizeHigh As UInteger
    Public nFileSizeLow As UInteger
    Public dwReserved0 As UInteger
    Public dwReserved1 As UInteger
    <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=260)> Public cFileName As String
    <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=14)> Public cAlternateFileName As String
End Structure

<DllImport("kernel32", CharSet:=CharSet.Unicode)>
Public Shared Function FindFirstFile(lpFileName As String, ByRef lpFindFileData As WIN32_FIND_DATA) As IntPtr
End Function

<DllImport("kernel32", CharSet:=CharSet.Unicode)>
Public Shared Function FindNextFile(hFindFile As IntPtr, ByRef lpFindFileData As WIN32_FIND_DATA) As Boolean
End Function

<DllImport("kernel32.dll")>
Public Shared Function FindClose(ByVal hFindFile As IntPtr) As Boolean
End Function

<DllImport("kernel32.dll", CharSet:=CharSet.Unicode, ExactSpelling:=False, SetLastError:=True)>
Public Shared Function DeleteFile(ByVal path As String) As Boolean
End Function

Public Shared Function GetFilenames(folderName As String) As List(Of String)
    Return GetNames(folderName, False)
End Function

Public Shared Function GetFolders(folderName As String) As List(Of String)
    Return GetNames(folderName, True)
End Function

Private Shared Function GetNames(folderName As String, getDirectories As Boolean) As List(Of String)
    Dim names As New List(Of String)
    Dim findData As New WIN32_FIND_DATA
    Dim findHandle As New IntPtr
    Dim INVALID_HANDLE_VALUE As New IntPtr(-1)

    If Not folderName.EndsWith("\") Then folderName += "\"
    ' Add wildcard to foldername to get all files
    folderName += "*"

    findHandle = FindFirstFile(folderName, findData)
    If findHandle <> INVALID_HANDLE_VALUE Then
        Do

            If findData.cFileName <> "." AndAlso findData.cFileName <> ".." Then
                Dim isDirectory As Boolean = (findData.dwFileAttributes And FileAttributes.Directory) = FileAttributes.Directory
                If (getDirectories AndAlso isDirectory) Or (Not getDirectories AndAlso Not isDirectory) Then
                    names.Add(findData.cFileName)
                End If
            End If

        Loop While (FindNextFile(findHandle, findData))
        FindClose(findHandle)
    End If

    Return names
End Function

结束班

2 个答案:

答案 0 :(得分:0)

如果你使用循环,你可以让程序继续,直到满足某个条件(例如删除所有扩展名为.example的文件) 研究while循环,他们应该能够做你想要的程序。

循环结构: https://msdn.microsoft.com/en-GB/library/ezk76t25.aspx

答案 1 :(得分:0)

这些方面的某些内容可能有所帮助:

Imports System.IO
Imports System.Runtime.InteropServices

Module Module1

Sub Main()
    Dim longFolderName As String = "\\?\c:\temp\"
    Dim extensionToDelete As String = ".xrl"

    RecursiveDelete(longFolderName, extensionToDelete)
End Sub

Sub RecursiveDelete(path As String, extensionToDelete As String)

    If Not path.EndsWith("\") Then path += "\"

    ' Handle all folders below this one
    Dim folders As List(Of String) = VeryLongFilenameHandler.GetFolders(path)
    For Each folder As String In folders
        RecursiveDelete(path + folder, extensionToDelete)
    Next

    ' Delete any applicable files
    Dim filenames As List(Of String) = VeryLongFilenameHandler.GetFilenames(path)

    For Each filename As String In filenames
        If filename.ToLower.EndsWith(extensionToDelete) Then
            VeryLongFilenameHandler.DeleteFile(path + filename)
        End If
    Next

End Sub
End Module

Class VeryLongFilenameHandler

<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)>
Structure WIN32_FIND_DATA
    Public dwFileAttributes As UInteger
    Public ftCreationTime As System.Runtime.InteropServices.ComTypes.FILETIME
    Public ftLastAccessTime As System.Runtime.InteropServices.ComTypes.FILETIME
    Public ftLastWriteTime As System.Runtime.InteropServices.ComTypes.FILETIME
    Public nFileSizeHigh As UInteger
    Public nFileSizeLow As UInteger
    Public dwReserved0 As UInteger
    Public dwReserved1 As UInteger
    <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=260)> Public cFileName As String
    <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=14)> Public cAlternateFileName As String
End Structure

<DllImport("kernel32", CharSet:=CharSet.Unicode)>
Public Shared Function FindFirstFile(lpFileName As String, ByRef lpFindFileData As WIN32_FIND_DATA) As IntPtr
End Function

<DllImport("kernel32", CharSet:=CharSet.Unicode)>
Public Shared Function FindNextFile(hFindFile As IntPtr, ByRef lpFindFileData As WIN32_FIND_DATA) As Boolean
End Function

<DllImport("kernel32.dll")>
Public Shared Function FindClose(ByVal hFindFile As IntPtr) As Boolean
End Function

<DllImport("kernel32.dll", CharSet:=CharSet.Unicode, ExactSpelling:=False, SetLastError:=True)>
Public Shared Function DeleteFile(ByVal path As String) As Boolean
End Function

Public Shared Function GetFilenames(folderName As String) As List(Of String)
    Return GetNames(folderName, False)
End Function

Public Shared Function GetFolders(folderName As String) As List(Of String)
    Return GetNames(folderName, True)
End Function

Private Shared Function GetNames(folderName As String, getDirectories As Boolean) As List(Of String)
    Dim names As New List(Of String)
    Dim findData As New WIN32_FIND_DATA
    Dim findHandle As New IntPtr
    Dim INVALID_HANDLE_VALUE As New IntPtr(-1)

    If Not folderName.EndsWith("\") Then folderName += "\"
    ' Add wildcard to foldername to get all files
    folderName += "*"

    findHandle = FindFirstFile(folderName, findData)
    If findHandle <> INVALID_HANDLE_VALUE Then
        Do

            If findData.cFileName <> "." AndAlso findData.cFileName <> ".." Then
                Dim isDirectory As Boolean = (findData.dwFileAttributes And FileAttributes.Directory) = FileAttributes.Directory
                If (getDirectories AndAlso isDirectory) Or (Not getDirectories AndAlso Not isDirectory) Then
                    names.Add(findData.cFileName)
                End If
            End If

        Loop While (FindNextFile(findHandle, findData))
        FindClose(findHandle)
    End If

    Return names
End Function

End Class

类VeryLongFilenameHandler有一个函数Ge​​tFilenames,它将返回使用Win32 API指定的文件夹中的文件列表。然后,您可以迭代这些文件名,检查扩展名并删除(如果适用)(再次使用Win32调用)。