Search filesystem for filepath using VBA - windows

I am looking for a way to search a specific folder for a subfolder containing a certain string. Below I have listed a function I typed off the top of my head to see if it would work. Well, it does work but when I am talking about searching through 6,000 folders on a network drive it just isn't fast enough.
I'm sure that there is a better way to do it but I can't seem to dig anything up on Google.
Is there an object that allows me to leverage the windows built in file system searching and indexing capabilities?
As an alternative, does someone have a way to optimize my code? The main bottleneck is the usage of instr.
Here is the code:
Function findPath(strId As String) As String
checkObj
Dim strBase As String
strBase = opt.photoBasePath
Dim fs As Object
Set fs = CreateObject("Scripting.FileSystemObject")
Dim baseFolder As Object
Set baseFolder = fs.getfolder(strBase)
Dim folder As Object
For Each folder In baseFolder.subfolders
If InStr(1, folder.name, strId) > 0 Then
findPath = strBase & "\" & folder.name
Exit Function
End If
Next folder
End Function
P.S. I'm sure someone will suggest modifying my folder structure so that I can programmatically predict the path but for various reason that isn't possible in my case.

You could use the FindFirstFile Win32 API, which allows you to search for files or sudirectories matching a specified name. Additionally, you could also use the FindFirstFileEx function, along with a FINDEX_SEARCH_OPS parameter of FindExSearchLimitToDirectories, which would limit your search to a file that matches a specified name and is also a directory (if the file system supports directory filtering). For more information on using these functions from VB/VBA see the following:
http://www.xtremevbtalk.com/showpost.php?p=1157418&postcount=4
http://support.microsoft.com/kb/185476
http://www.ask-4it.com/how-to-use-findfirstfile-win32-api-from-visual-basic-code-2-ca.html

Consider splitting traversing the folders from finding your key. Instead of the instr test, store the folder names in a table, then use a query on the table to find your target. It might be slower, but searching should be faster.

Related

Looping over all databases in a directory

I need to loop over all databases in a certain directory, where the database name is ACPwxyz.mdb, where wxyz is the equivalent to an MMYY value for the period that database was used for.
E.g., the database for July 2017 would be ACP0717.mdb.
I've never written in VB6 before and I totally hate it, but it's an extension to an existing project so I'm stuck with it!
Is there a way of looping over all files in a directory, checking if the file name follows the format of ACPwxyz.mdb or not, and if it does, then opening a connection to it?
I've looked around a bit and see Dir(x, y), but I'm not sure if I can use this in this situation?
Any tips would be appreciated.
You can use Dir, yes.
If you use something like this:
Dim strFile As String
strFile = Dir(yourDBPath, "ACP????.mdb") ' mdb for MS-Access files
Do Until strFile = ""
If Len(strFile) = 11 Then ' Ensure the DB file name is 11 characters, which yours are
'Do something // You can also check the file name doesn't = a certain name if needed
End If
strFile = Dir
Loop
Dir accepts either an asterisk (*), or a question mark (?) as wildcards in file names, so this will look for any database in the set path that is called ACP followed by 4 characters.

Iterate over pre-filtered list of folders

I'm working with a client's flat folder structure that has a single folder containing 45k subfolders with 8-digit folder names, e.g. 51023231. I have a small script that ripples through them and copies them into a bin-sorted set of subfolders elsewhere on the network (for use with SharePoint), such that the first 5 digits are used as a parent folder, i.e. the contents of 51023231 are copied into 51023\51023231. It works perfectly well, and I've managed to some modest optimisation when dealing with folders new to the destination.
However, it can take an hour or so to run over the entire 45k set of folders doing folder by folder comparisons, I was wondering if it was possible to run a system-level query to return only an initial list of folders whose modification dates were after a given point, and then run the existing script over that. I've done the usual Google-is-your-friend type trawl, and keep hitting the idea of using WMI to do this, but I don't get much further. Is this because it simply isn't possible with VBScript?
Any pointers gratefully received.
It's possible with VBScript using WMI. It's not something you'd be able to do using the FileSystemObject, if that's what you're implying.
You can query WMI's Win32_Directory class to filter folders by modified date. The only tricky part is the datetime format used by WMI. But the SWbemDateTime class can convert a VBScript date to a datetime value.
Here's an example:
' Create a datetime value for use in our WMI query...
Dim dt
Set dt = CreateObject("WbemScripting.SWbemDateTime")
dt.SetVarDate DateSerial(2015, 8, 31)
Dim objWMI
Set objWMI = GetObject("winmgmts:\\.\root\cimv2")
' Find all subfolders of 'c:\some\path' that were modified > 2015/08/31
Dim objFolders
Set objFolders = objWMI.ExecQuery("select * from Win32_Directory" _
& " where Drive='C:' and Path='\\some\\path\\' and LastModified>'" & dt & "'")
Dim objFolder
For Each objFolder in objFolders
WScript.Echo objFolder.Name
Next

VBS - Replace certain text entries in various files

I created a template for my test suite in QTP where the level of abstraction (parameterization) is sufficiently good.
I would now need to populate a new test suite from the existing pattern, thus replacing certain entries with other ones in various files.
For example one of the words I deliberately put in the script suite pattern is [Template], therefore I would need to copy and paste the template with a different name, change all the entries by [Template] to the new string and so forth.
Any code would be appreciated as my VBScript skills are not optimal ;)
Thanks in advance!
Use this demo script:
Option Explicit
Dim gMap : Set gMap = Createobject("Scripting.Dictionary")
Function replGMap(sM, nPos, sSrc)
replGMap = gMap(sM)
End Function
Dim reMap : Set reMap = New RegExp
reMap.Global = True
reMap.Pattern = "\[\w+\]"
gMap("[A]") = "abra"
gMap("[B]") = "cadabra"
WScript.Echo reMap.Replace("1[A]2[A]3[B]4[A]5", GetRef("replGMap"))
output:
abra2abra3cadabra4abra5
as a list of keywords to look up in the VBScript Docs. For using a function in .Replace, see here.
The FileSystemObject provides the means (Open/CreateTextFile, ReadAll, Write) to read and write files.

Accessing a hidden share programmatically in VB.net

I have a simple method to move a folder to a new directory
Dim firstshare As String = "\\myshare\users\" & frmDeparture.txtUsername.Text
Dim destination As String = "\\secondshare\userarchives$\" & frmDeparture.txtUsername.Text
Try
If Directory.Exists(firstshare) Then
Directory.Move(firstshare, destination)
MsgBox("Folder moved from \\firstshare\users")
End If
Catch ex As Exception
MsgBox("Error finding folder")
End Try
This works fine if I set "destination" as a path like "\path\whatever", but if it's a hidden path (with the $) it doesn't work. Is there something special I have to do in order to access a hidden share programatically?
You are most likely trying to move a directory from one volume/partition to another, and you are getting this error :
Source and destination path must have identical roots. Move will not
work across volumes
An explanation of why this is not possible is found Here. The only way you could move directories across different volumes is to create a new directory in the destination volume and copy the files from the source. You could then delete the original files if you wish.

Windows / NTFS: Number of files in a directory, without enumerating them

Is there a way in Windows to get the number of files in a directory (non-recursively is good enough) without the potentially significant overhead of enumerating them all through FindFirst/NextFile?
The purpose is for an estimate how many files need to be processed.
The directory structure is known and not deep, and folders usually don't contain unknown files.
Since the data is not essential to continue and the folder is virtually always on a local drive, an NTFS-specific command would be acceptable (provided that does not require elevation).
Any ideas?
Keeping track of the number of files in a directory is an overhead that doesn't provide any benefit for a file system, so none of them do it.
Counting files on a local drive should be fast enough for most purposes. It will certainly take a small fraction of the time needed to process the files.
Assuming that Indexing service is running and the directory is indexed, we can query the catalog and count the files on a given directory.
I dont know if querying the catalog is faster, its the only idea came on my mind.
Regards.
Sample code in VB.NET
Sub Main()
Try
' Catalog Name
Dim strCatalog As String = "System"
Dim strQuery As String
strQuery = "Select DocPageCount,DocTitle,Filename,Size,PATH,URL from SCOPE('shallow traversal of ""C:\Windows""')"
Dim connString As String = "Provider=MSIDXS.1;Integrated Security .='';Data Source='" & strCatalog & "'"
Dim cn As New System.Data.OleDb.OleDbConnection(connString)
cn.Open()
Dim cmd As New System.Data.OleDb.OleDbCommand(strQuery, cn)
Dim rdr As System.Data.OleDb.OleDbDataReader = cmd.ExecuteReader()
Dim files As Integer = 0
While rdr.Read()
files += 1
Console.WriteLine("Path: {0} Filename: {1} Size : {2}", rdr("PATH"), rdr("Filename"), rdr("Size"))
End While
rdr.Close()
rdr = Nothing
cmd.Dispose()
cmd = Nothing
cn.Close()
Console.WriteLine("Total Files: {0}", files)
Catch ex As Exception
Console.WriteLine(ex)
End Try
End Sub
More info: Searching your web site with the Microsoft Indexing Service and ASP.NET

Resources