¿No se puede usar algún separador de expresión?
He intentado esto:
IO.Directory.GetFiles(Directory, "*.exe, *.vb")
IO.Directory.GetFiles(Directory, "*.exe; *.vb")
IO.Directory.GetFiles(Directory, "*.exe" + "*.vb")
IO.Directory.GetFiles(Directory, "*.exe" + IO.Path.AltDirectorySeparatorChar + "*.vb")
IO.Directory.GetFiles(Directory, "*.exe" + IO.Path.DirectorySeparatorChar + "*.vb")
Hasta donde se no :-\ Puedes obtener todos los resultados y filtrar, o bien puedes buscar varias veces, pero no directamente :-\
Saludos
Tal vez te sirva esto:
http://stackoverflow.com/questions/163162/can-you-call-directory-getfiles-with-multiple-filters (http://stackoverflow.com/questions/163162/can-you-call-directory-getfiles-with-multiple-filters)
Un saludo
Puf, para perder tiempo de lectura de disco haciendo múltiples búsquedas y/o filtrando la lista... busco algo más "natural"
creo que jamás diría esto, pero es que para eso es mejor usar el comando "DIR" de la CMD (en VB.NET) sincéramente xD.
@3mp3z@ndo
Gracias por la info , parece la mejor opción pero me queda la duda,
¿Esto solo hace una búsqueda y filtra, o hace dos búsquedas?
Dim files = Directory.GetFiles("C:\", "*").Where(Function(s) s.EndsWith(".exe") OrElse s.EndsWith(".xml"))
Cita de: EleKtro H@cker en 18 Enero 2013, 13:17 PM
¿Esto solo hace una búsqueda y filtra, o hace dos búsquedas?
Dim files = Directory.GetFiles("C:\", "*").Where(Function(s) s.EndsWith(".exe") OrElse s.EndsWith(".xml"))
Primero listas todos los archivos (*.*) y luego filtras en memoria
Saludos
Como se podría optimizar el código para crear una función de esto?
Por ejemplo:
Private Sub Form1_Load()
Dim File_Extensions() As String = {"*.txt", "*.ini", "*.exe", "*.pdf"}
Dim Files() = Get_Files_By_FileExtensions("C:\", File_Extensions)
End Sub
Y entonces aquí se debería agregar automáticamente un "orelse s.EndsWith(siguiente extensión)" por cada extensión de la colección:
Public Function Get_Files_By_FileExtensions(ByVal Directory As String, ByVal Extensions() As String) As System.IO.FileInfo()
Return IO.Directory.GetFiles(Directory, "*").Where(Function(s) s.EndsWith(Extensions(0)) _
OrElse s.EndsWith(Extensions(1)) _
OrElse s.EndsWith(Extensions(2)) _
OrElse s.EndsWith(Extensions(3)))
End Function
¿Es posible hacerlo?
EDITO: Yo ya tengo funciones para listar archivos, pero preciso hacerlo con ese código que menciono (me resulta más limpio porque sólo hace una búsqueda)
si quieres algo rapido y optimo, usas apis, regular expresion,
Cita de: _katze_ en 26 Enero 2013, 18:18 PM
si quieres algo rapido y optimo, usas apis, regular expresion,
Gracias, pero podrías indicarme (para buscar info) con que API y que función
_katze_?
codigo vieejo y con ayuda de varias, pero la connserve y justo t viene para aprender
Imports System.Runtime.InteropServices
Imports System.Text.RegularExpressions
Imports System.Text
Imports System.IO
Public Class ClsBucarFiles
#Region " Icon "
Private Structure SHFILEINFO
Public hIcon As IntPtr ' : icon
Public iIcon As Integer ' : icondex
Public dwAttributes As Integer ' : SFGAO_ flags
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=260)> _
Public szDisplayName As String
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=80)> _
Public szTypeName As String
End Structure
Private Declare Ansi Function SHGetFileInfo Lib "shell32.dll" (ByVal pszPath As String, _
ByVal dwFileAttributes As Integer, ByRef psfi As SHFILEINFO, ByVal cbFileInfo As Integer, _
ByVal uFlags As Integer) As IntPtr
Private Const SHGFI_SMALLICON As Long = &H1
Private Const SHGFI_SYSICONINDEX As Long = &H4000
Private Const SHGFI_USEFILEATTRIBUTES As Long = &H10
Private Const SHGFI_TYPENAME As Long = &H400
Private Const SHGFI_DISPLAYNAME As Long = &H200
Private Const SHGFI_ICON = &H100
Private Const SHGFI_LARGEICON = &H0 ' Large icon
Private Shared shfitmp As SHFILEINFO 'just used for the following
Private Shared SHFILESIZE As Integer = Marshal.SizeOf(shfitmp.GetType())
Public Function ptricon(ByVal vsPath As String) As IntPtr
Dim hImgSmall As IntPtr
Dim shinfo As New SHFILEINFO()
shinfo.szDisplayName = New String(Chr(0), 260)
shinfo.szTypeName = New String(Chr(0), 80)
hImgSmall = SHGetFileInfo(vsPath, 0&, shinfo, SHFILESIZE, _
SHGFI_ICON Or SHGFI_SYSICONINDEX Or SHGFI_SMALLICON)
Return (shinfo.hIcon)
End Function
#End Region
#Region " Declaraciones "
<DllImport("kernel32.dll")> _
Private Shared Function FindClose(ByVal hFindFile As IntPtr) As Boolean
End Function
<DllImport("kernel32.dll", CharSet:=CharSet.None)> _
Private Shared Function FindFirstFile(ByVal lpFileName As String, ByRef lpFindFileData As WIN32_FIND_DATA) As IntPtr
End Function
Private Declare Function FindNextFile Lib "kernel32" Alias "FindNextFileA" (ByVal hFindFile As IntPtr, ByRef lpFindFileData As WIN32_FIND_DATA) As Boolean
<StructLayout(LayoutKind.Sequential)> _
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
Public Event FileFound(ByVal sPath As String, ByVal sFile As String, ByVal atributos As FileAttributes)
Public Event FolderFound(ByVal sPath As String, ByVal sFolder As String, ByVal atributos As FileAttributes)
Private cancel As Boolean = False
Private INVALID_HANDLE_VALUE As New IntPtr(-1)
Private RegExp As Regex
Private sbFiles As New StringBuilder
Private sbFolders As New StringBuilder
#End Region
#Region " PRocedimientos "
Public Sub New()
MyBase.New()
End Sub
Public Sub start()
If RegExp Is Nothing Then
RegExp = New Regex(p_match, RegexOptions.IgnoreCase)
Else
RegExp = Nothing
RegExp = New Regex(p_match, RegexOptions.IgnoreCase)
End If
cancel = False
Dim arrdrive() As String
arrdrive = p_path.Split(Chr(59))
For Each s As String In arrdrive
Call SubBusqueda(s) 'recursividad xD
Next
End Sub
Public Sub Cancelar()
cancel = True
End Sub
Private Function StripNulls(ByVal sData As String) As String
StripNulls = Left$(sData, Len(sData))
End Function
Private Sub SubBusqueda(ByVal vsPath As String)
Dim ptrSearch As New IntPtr
Dim vsfile As String = String.Empty
Dim vsfolder As String = String.Empty
Dim vaDir As New ArrayList
Dim wfd As New WIN32_FIND_DATA
Dim dir As String = String.Empty
Dim ret As Boolean
If cancel Then Exit Sub
Call NormalizePath(vsPath)
ptrSearch = FindFirstFile(vsPath & "*", wfd)
If Not ptrSearch = INVALID_HANDLE_VALUE Then
Do
If (wfd.dwFileAttributes And FileAttributes.Directory) <> FileAttributes.Directory Then
vsfile = StripNulls(wfd.cFileName)
If Not p_hide Then
If (wfd.dwFileAttributes And FileAttributes.Hidden) = FileAttributes.Hidden Then GoTo FNEXT
End If
If RegExp.Matches(vsfile).Count = 0 Then GoTo FNEXT
sbFiles.AppendLine(vsfile)
RaiseEvent FileFound(vsPath, vsfile, CType(wfd.dwFileAttributes, FileAttributes))
Else
If Not p_hide Then
If (wfd.dwFileAttributes And FileAttributes.Hidden) = FileAttributes.Hidden Then GoTo FNEXT
End If
vsfolder = StripNulls(wfd.cFileName)
If (vsfolder <> ".") And (vsfolder <> "..") Then
dir = vsPath & vsfolder & "\"
If Not p_sys Then
If dir = Environ("Windir") & "\" Then GoTo FNEXT
End If
vaDir.Add(dir)
If RegExp.Matches(vsfolder).Count = 0 Then GoTo FNEXT
sbFolders.AppendLine(vsfolder)
RaiseEvent FolderFound(vsPath, vsfolder, CType(wfd.dwFileAttributes, FileAttributes))
End If
End If
FNEXT:
If cancel Then FindClose(ptrSearch) : Exit Sub
Application.DoEvents()
ret = FindNextFile(ptrSearch, wfd)
Loop While ret
Call FindClose(ptrSearch)
End If
If p_subfolder Then
For i As Integer = 0 To vaDir.Count - 1
Call SubBusqueda(CStr(vaDir(i)))
Next
End If
End Sub
Private Function drivers() As String
Dim drive As DriveInfo
Dim dr As New StringBuilder
For Each drive In DriveInfo.GetDrives
With drive
If .IsReady Then
dr.Append(drive.Name & ";")
End If
End With
Next
Return dr.ToString
End Function
Private Function ReplaceFilter(ByVal sFilter As String) As String
sFilter = sFilter.Replace("+", "\+")
sFilter = sFilter.Replace(".", "\.")
sFilter = sFilter.Replace("|", "\|")
sFilter = sFilter.Replace(";", "|\b")
sFilter = sFilter.Replace(" ", "|\b")
sFilter = sFilter.Replace("{", "\{")
sFilter = sFilter.Replace("}", "\}")
sFilter = sFilter.Replace("*", ".+")
sFilter = sFilter.Replace("?", ".{1}")
sFilter = sFilter.Replace("(", "\(")
sFilter = sFilter.Replace(")", "\)")
sFilter = sFilter.Replace("^", "\^")
sFilter = sFilter.Replace("$", "\$")
sFilter = sFilter.Replace("[", "\[")
sFilter = sFilter.Replace("[", "\]")
Do While CBool(InStr(sFilter, "|\b|\b"))
sFilter = Replace$(sFilter, "|\b|\b", "|\b")
Loop
Return "^(" & sFilter & ")$|(" & sFilter & ".+)"
End Function
Public Function NormalizePath(byval sData As String) As String
If Strings.Len(sData) > 1 Then
sData = Strings.Replace(sData, "/", "\")
If Not Strings.Right(sData, 1) = "\" Then
Return sData & "\"
Else
Return sData
End If
End If
End Function
#End Region
#Region " propiedades "
Private p_match As String = String.Empty
WriteOnly Property Match() As String
Set(ByVal value As String)
p_match = ReplaceFilter(value)
End Set
End Property
Private p_subfolder As Boolean = False
Property SubFolder() As Boolean
Get
Return p_subfolder
End Get
Set(ByVal value As Boolean)
p_subfolder = value
End Set
End Property
Private p_hide As Boolean = False
Property HideFolder() As Boolean
Get
Return p_hide
End Get
Set(ByVal value As Boolean)
p_hide = value
End Set
End Property
Private p_sys As Boolean = False
Property SysFolder() As Boolean
Get
Return p_sys
End Get
Set(ByVal value As Boolean)
p_sys = value
End Set
End Property
Private p_path As String = drivers()
Property Path() As String
Get
Return p_path
End Get
Set(ByVal value As String)
p_path = NormalizePath(value)
End Set
End Property
ReadOnly Property FilesString() As String
Get
Return sbFolders.ToString
End Get
End Property
ReadOnly Property FolderString() As String
Get
Return sbFolders.ToString
End Get
End Property
#End Region
End Class
El código no está mal pero ... si miras el código interno de IO.Directory.GetFiles verás que hace uso de la siguiente clase, y de las mismas API<Serializable, StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto), BestFitMapping(False)> _
Friend Class WIN32_FIND_DATA
Friend dwFileAttributes As Integer
Friend ftCreationTime_dwLowDateTime As UInt32
Friend ftCreationTime_dwHighDateTime As UInt32
Friend ftLastAccessTime_dwLowDateTime As UInt32
Friend ftLastAccessTime_dwHighDateTime As UInt32
Friend ftLastWriteTime_dwLowDateTime As UInt32
Friend ftLastWriteTime_dwHighDateTime As UInt32
Friend nFileSizeHigh As Integer
Friend nFileSizeLow As Integer
Friend dwReserved0 As Integer
Friend dwReserved1 As Integer
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=260)> _
Friend cFileName As String
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=14)> _
Friend cAlternateFileName As String
<TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")> _
Public Sub New()
End Class
Saludos :P
pero al hacerlo con mi clase no necesits permisos de administrador ni ninguna magia negra. como con el frame :-*
A pesar de la bonita Class de _katze_ (por cierto, gracias), y después de mucho buscar la manera más óptima ...al final me quedo con esta función:
Private Function Get_Files(ByVal Path As String, ParamArray exts() As String) As List(Of IO.FileInfo)
Return New IO.DirectoryInfo(Path).GetFiles.Where(Function(o) exts.Contains(o.Extension)).ToList
End Function
For Each file In Get_Files("C:\Windows", {".dll", ".ini"}) : MsgBox(file.Name) : Next
Más sencillo y eficaz creo que sería imposible!
Lo malo es que no se me ocurre como hacer para que la función me permita buscar de manera recursiva,
me gustaría poder implementar la recursividad en esa función, preservando su maravillosa sencillez, elegancia y eficacia, es decir...que no quiero llenar la función de Fors para hacer largos recorridos en los subdirectorios estropeando la performance de la función.
¿Alguien tiene idea de que modificaciones necesita la función para hacerla recursiva?
Ahora sí, mejor imposible!, aquí tienen la forma más eficiente:
Private Function Get_Files(ByVal rootDirectory As String, ByVal recursive As Boolean, ParamArray exts() As String) As List(Of IO.FileInfo)
Dim searchOpt As IO.SearchOption = If(recursive, IO.SearchOption.AllDirectories, IO.SearchOption.TopDirectoryOnly)
Return IO.Directory.GetFiles(rootDirectory, "*.*", searchOpt).Where(Function(o) exts.Contains(IO.Path.GetExtension(o))).Select(Function(p) New IO.FileInfo(p)).ToList
End Function
Ejemplo de uso:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For Each file In Get_Files("C:\Windows", True, {".dll", "DLL"}) : MsgBox(file.Name) : Next
End Sub
EDITO: Lo único imperfecto es que no es Ignore case, así que habría que usar la función así:
For Each file In Get_Files("C:\Windows", True, {".dll", "DLL"}) : MsgBox(file.Name) : Next
;D