
Buscar el archivo más reciente con un nombre similar en una carpeta
Estaba trabajando en un proyecto y me encontré con un pequeño problema. Verás, creé un programa que procesa archivos generados por una aplicación web y que se descargan en la PC del usuario. El problema es que si el archivo ya existe, Windows agrega un prefijo numérico para diferenciar los archivos.
Entonces, digamos que los archivos originales se llamaban ‘DataArchive.zip’, las descargas posteriores dan como resultado
- Archivo de datos.zip’
- Archivo de datos (1).zip’
- Archivo de datos (2).zip’
- Archivo de datos (3).zip’
- …
Bueno, eso es en Windows 10. Microsoft intentó ayudarnos y en Windows 11 ahora agrega un espacio adicional, por lo que obtenemos:
- Archivo de datos.zip’
- Archivo de datos (1).zip’
- Archivo de datos (2).zip’
- Archivo de datos (3).zip’
- …
Ya sabes, sólo para darle un poco de vida a nuestra vida de codificación.
Busqué en Google, pensando que no sería el primer desarrollador que necesitara hacer este tipo de cosas, pero no encontré nada. Mi GoogleFu no estaba a la altura.
Por eso, me propuse crear algo por mi cuenta. Quería idear una forma «sencilla» de buscar en una carpeta, en este caso la carpeta de descargas, el último archivo descargado con un patrón de nombre determinado.
¿Cómo se podría hacer?
Bueno, terminé recurriendo al objeto del sistema de archivos (FSO). Esperaba poder usar simplemente Dir(), pero no me proporcionó acceso a las propiedades de archivo necesarias que sí ofrecía FSO.
Esto es lo que se me ocurrió:
'---------------------------------------------------------------------------------------
' Procedure : FindLatestFile
' Author : Daniel Pineault, CARDA Consultants Inc.
' Website :
' Purpose : Find the latest (DateCreated) file based on a search pattern
' Copyright : The following is release as Attribution-ShareAlike 4.0 International
' (CC BY-SA 4.0) -
' Req'd Refs: Late Binding -> none required
' References:
'
' Input Variables:
' ~~~~~~~~~~~~~~~~
' sPath : Directory to search through
' sSearchPattern : Search pattern to use to identify matching files
'
' Usage:
' ~~~~~~
' FindLatestFile("C:\Users\Dev\Downloads\", "DataArchive (*).zip")
' Returns -> DataArchive (4).zip
'
' Revision History:
' Rev Date(yyyy-mm-dd) Description
' **************************************************************************************
' 1 2024-07-15 Initial Public Release
'---------------------------------------------------------------------------------------
Function FindLatestFile(ByVal sPath As String, _
ByVal sSearchPattern As String) As Variant
On Error GoTo Error_Handler
Dim oFSO As Object 'Scripting.FileSystemObject
Dim oFolder As Object 'Scripting.Folder
Dim oFile As Object 'Scripting.File
Dim dtCurrFileDt As Date
Dim dtFileDt As Date
Dim CurrentRow As Long
Dim sOutputFile As String
Set oFSO = CreateObject("Scripting.FileSystemObject")
Set oFolder = oFSO.GetFolder(sPath)
For Each oFile In oFolder.Files
If oFile.Name Like sSearchPattern Then
dtCurrFileDt = oFile.DateCreated
If CurrentRow = 0 Then
dtFileDt = oFile.DateCreated
sOutputFile = oFile.Name
Else
If dtCurrFileDt > dtFileDt Then
dtFileDt = oFile.DateCreated
sOutputFile = oFile.Name
End If
End If
CurrentRow = CurrentRow + 1
End If
Next oFile
If sOutputFile = "" Then
FindLatestFile= Null
Else
FindLatestFile= sOutputFile
End If
Error_Handler_Exit:
On Error Resume Next
Set oFile = Nothing
Set oFolder = Nothing
Set oFSO = Nothing
Exit Function
Error_Handler:
MsgBox "The following error has occurred" & vbCrLf & vbCrLf & _
"Error Source: FindLatestFile" & vbCrLf & _
"Error Number: " & Err.Number & vbCrLf & _
"Error Description: " & Err.Description & _
Switch(Erl = 0, "", Erl 0, vbCrLf & "Line No: " & Erl) _
, vbOKOnly + vbCritical, "An Error has Occurred!"
Resume Error_Handler_Exit
End Function
y un ejemplo de su uso podría ser:
sArchive = FindLatestFile("C:\Users\Dev\Downloads\", "DataArchive(*).zip") 'Windows 10 Search Pattern
If IsNull(sArchive) Then sArchive = FindLatestFile("C:\Users\Dev\Downloads\", "DataArchive (*).zip") 'Windows 11 Search Pattern
If IsNull(sArchive) Then sArchive = "DataArchive.zip" 'If none found fall back to the original filename
'Check if sArchive Exist ...
y esto se puede utilizar para todo tipo de otros escenarios, todo lo que tienes que hacer es cambiar sSearchPattern por el patrón que satisfaga tus necesidades.
En una versión futura, permitiré múltiples patrones en lugar de requerir procesar una carpeta varias veces, para mejorar el rendimiento, pero eso será para otro día.