Access VBA search folders and Subfolders and append results to table - ms-access

I'm using Access 2013 and have a small program to lookup all images in a folder path that is passed to it. It then appends each of these paths to a table called "tblImages". The only problem is it only ever returns the first image in each folder\sub folder i.e. 1 image from each folder and ignores the rest. How do I modify it to search for and append every single image in each folder\sub folder?
Public Sub listImages(folderPath As String)
'define variables
Dim fso As Object
Dim objFolder As Object
Dim objFolders As Object
Dim objF As Object
Dim objFile As Object
Dim objFiles As Object
Dim strFileName As String
Dim strFilePath As String
Dim myList As String
Dim rst As DAO.Recordset
'set file system object
Set fso = CreateObject("Scripting.FileSystemObject")
'set folder object
Set objFolder = fso.GetFolder(folderPath)
'set files
Set objFiles = objFolder.files
Set objFolders = objFolder.subfolders
'list all images in folder
For Each objFile In objFiles
If Right(objFile.Name, 4) = ".jpg" Then
strFileName = objFile.Name
strFilePath = objFile.path
myList = myList & strFileName & " - " & strFilePath & vbNewLine
End If
Next
'go through all subflders
For Each objF In objFolders
'call same procedure for each subfolder
Call listImages(objF.path)
Next
Set rst = CurrentDb.OpenRecordset("tblImages", dbOpenDynaset, dbSeeChanges)
With rst
.AddNew
.Fields("Image") = strFileName
.Fields("FilePath") = strFilePath
.Update
End With
'Debug.Print myList
Set objFolder = Nothing
Set objFolders = Nothing
Set objFile = Nothing
Set objF = Nothing
Set fso = Nothing
End Sub

You were very close. You can put this in a class module named FileSearch
Option Compare Database
Option Explicit
Private fso As FileSystemObject
Public ExtensionFilters As Dictionary
Private Sub Class_Initialize()
Set fso = New FileSystemObject
End Sub
Public Sub listImages(folderPath As String)
'define variables
Dim objFolder As Folder
Dim objFolders As Folders
Dim objF As Folder
Dim objFile As File
Dim objFiles As Files
Dim strFileName As String
Dim strFilePath As String
Dim myList As String
Dim rst As DAO.Recordset
If Not fso.FolderExists(folderPath) Then Exit Sub
'set folder object
Set objFolder = fso.GetFolder(folderPath)
'set files
Set objFiles = objFolder.Files
Set objFolders = objFolder.SubFolders
'list all images in folder
For Each objFile In objFiles
If Not ExtensionFilters Is Nothing Then
If ExtensionFilters.Exists(fso.GetExtensionName(objFile.path)) Then
strFileName = objFile.Name
strFilePath = objFile.path
AddImageToTable strFileName, strFilePath
End If
End If
Next
'go through all subflders
For Each objF In objFolders
'call same procedure for each subfolder
Call listImages(objF.path)
Next
End Sub
Private Sub AddImageToTable(strFileName, strFilePath)
Debug.Print strFileName, strFilePath
' change as needed
' Set rst = CurrentDb.OpenRecordset("tblImages", dbOpenDynaset, dbSeeChanges)
' With rst
' .AddNew
' .Fields("Image") = strFileName
' .Fields("FilePath") = strFilePath
' .Update
' End With
End Sub
and call it like this from wherever
Dim fs As New FileSearch
Dim ExtensionFilters As New Dictionary
ExtensionFilters.Add "jpg", "jpg"
ExtensionFilters.Add "jpeg", "jpeg"
Set fs.ExtensionFilters = ExtensionFilters
fs.listImages "C:\Users\bradley_handziuk\Downloads"
Also relevant is the DIR function.

Related

MS Access VBA lookup image file names from table, search for them and copy them

I'm using Access 2013. I have a list of images in a table. I then need to search through a set of folders (including sub folders), locate the images and copy them to a new directory. The table that contains the image names does not reference the file path.
What is the best way to achieve this? Is it possible to loop through the table and perform the search, or would I have break it down and manually locate each file and update a flag to say it exists, then go back and copy them?
Not sure how to do this but would appreciate any ideas.
Thanks.
For some import programs I had to manipulate files, create copies etc. and I created some functions to help process, you might find some use in them:
To create folder from VBA:
Public Function folderCreate(filePath As String) As Boolean
'define variables
Dim fsoFold As Object
'set file system object
Set fsoFold = CreateObject("Scripting.FileSystemObject")
If Not fsoFold.folderExists(filePath) Then
'check if folder exists
fsoFold.CreateFolder (filePath)
End If
folderCreate = True
Set fsoFold = Nothing
End Function
To check if folder exists:
Public Function folderExists(folderPath As String) As Boolean
'define variables
Dim fso As Object
'set file system object
Set fso = CreateObject("Scripting.FileSystemObject")
'check if file exists
If fso.folderExists(folderPath) Then
folderExists = True
Else
folderExists = False
End If
Set fso = Nothing
End Function
To check if file exists:
Public Function fileExists(filePath As String) As Boolean
'define variables
Dim fso As Object
'set file system object
Set fso = CreateObject("Scripting.FileSystemObject")
'check if file exists
If fso.fileExists(filePath) Then
fileExists = True
Else
fileExists = False
End If
Set fso = Nothing
End Function
Similar to this, use movefile to move it to new location.
fso.movefile strFullPath, strFullBackUp
EDIT: Following sub will go through given folder and list all JPG images - this code is just example how to find files, folders and how to recursively go through them.
Public Sub listImages(folderPath As String)
'define variables
Dim fso As Object
Dim objFolder As Object
Dim objFolders As Object
Dim objF As Object
Dim objFile As Object
Dim objFiles As Object
Dim strFileName As String
Dim strFilePath As String
Dim myList As String
'set file system object
Set fso = CreateObject("Scripting.FileSystemObject")
'set folder object
Set objFolder = fso.GetFolder(folderPath)
'set files
Set objFiles = objFolder.files
Set objFolders = objFolder.subfolders
'list all images in folder
For Each objFile In objFiles
If Right(objFile.Name, 4) = ".jpg" Then
strFileName = objFile.Name
strFilePath = objFile.Path
myList = myList & strFileName & " - " & strFilePath & vbNewLine
End If
Next
'go through all subflders
For Each objF In objFolders
'call same procedure for each subfolder
Call listImages(objF.Path)
Next
Debug.Print myList
Set objFolder = Nothing
set objFolders = Nothing
Set objFile = Nothing
set objF = Nothing
Set fso = Nothing
End Sub

Omit Folders From Recursive File Search

I was running a recursive file search procedure, and my computer shut down. I know what directory the procedure stopped at, is there a way I can specify a start folder for a recursive file search? For example, let's say this is my structure
R:\
R:\Test\
R:\Test\Folder1\
R:\Test1\
R:\Test1\Folder1\
R:\Test2\
R:\Test2\Folder2\
if I wanted the recursive search to start at
R:\Test1\Folder1\
how would the procedure go?
Option Compare Database
Sub ScanTablesWriteDataToText()
Dim Fileout As Object
Dim fso As Object
Dim objFSO As Object
Dim accapp As Access.Application
Dim db As DAO.Database
Dim tdf As DAO.TableDef
Dim colFiles As Collection
Set objFSO = CreateObject("Scripting.FileSystemObject")
Dim objRegExp As Object
Set objRegExp = CreateObject("VBScript.RegExp")
objRegExp.Pattern = ".jpg"
objRegExp.IgnoreCase = True
Set colFiles = New Collection
RecursiveFileSearch "R:\", objRegExp, colFiles, objFSO
For Each f In colFiles
'do something
Next
Set objFSO = Nothing
Set objRegExp = Nothing
End Sub
Sub RecursiveFileSearch(ByVal targetFolder As String, ByRef objRegExp As Object, _
ByRef matchedFiles As Collection, ByRef objFSO As Object)
Dim objFolder As Object
Dim objFile As Object
Dim objSubFolders As Object
Set objFolder = objFSO.GetFolder(targetFolder)
For Each objFile In objFolder.files
If objRegExp.test(objFile) Then
matchedFiles.Add (objFile)
End If
Next
Set objSubFolders = objFolder.Subfolders
For Each objSubfolder In objSubFolders
RecursiveFileSearch objSubfolder, objRegExp, matchedFiles, objFSO
Next
Set objFolder = Nothing
Set objFile = Nothing
Set objSubFolders = Nothing
End Sub
I'd change your recursive sub to include two more parameters -- one for the folder you're trying to find, and a boolean to indicate whether or not it's been found:
Sub RecursiveFileSearch(ByVal targetFolder As String, ByRef objRegExp As Object, _
ByRef matchedFiles As Collection, ByRef objFSO As Object, _
ByVal startFolder As String, ByVal found As Boolean)
Dim objFolder As Object
Dim objFile As Object
Dim objSubFolders As Object
Set objFolder = objFSO.GetFolder(targetFolder)
If startFolder = "" Or found Then
For Each objFile In objFolder.files
If objRegExp.test(objFile) Then
matchedFiles.Add (objFile)
End If
Next
End If
Set objSubFolders = objFolder.Subfolders
For Each objSubFolder In objSubFolders
If objSubFolder = startFolder Then
found = True
End If
RecursiveFileSearch objSubFolder, objRegExp, matchedFiles, objFSO, _
startFolder, found
Next
Set objFolder = Nothing
Set objFile = Nothing
Set objSubFolders = Nothing
End Sub
When you call it, it would be:
RecursiveFileSearch "R:\", objRegExp, colFiles, objFSO, "R:\Test1\Folder1\", false
You could short-cut this by running an (elegant) PowerShell
Dumps recursive JPG list to C:\temp\filename.csv
Sub Comesfast()
X2 = Shell("powershell.exe get-childitem ""C:\Test1\Folder1"" -recurse | where {$_.extension -eq "".jpg""} | Select-Object FullName| export-csv ""C:\temp\filename.csv"" ", 1)
End Sub

list files in folder and subfolders and output the result in multiple files for each parent folder

I am using the code for listing files in a folder.
Dim fso
Dim ObjOutFile
Set fso = CreateObject("Scripting.FileSystemObject")
Set ObjOutFile = fso.CreateTextFile(GetFiles(FolderName) & "_"&"OutputFiles.csv")
ObjOutFile.WriteLine("Type,File Name,File Path")
GetFiles("YOUR LOCATION")
ObjOutFile.Close
WScript.Echo("Completed")
Function GetFiles(FolderName)
On Error Resume Next
Dim ObjFolder
Dim ObjSubFolders
Dim ObjSubFolder
Dim ObjFiles
Dim ObjFile
Set ObjFolder = fso.GetFolder(FolderName)
Set ObjFiles = ObjFolder.Files
For Each ObjFile In ObjFiles
ObjOutFile.WriteLine("File," & ObjFile.Name & "," & ObjFile.Path)
Next
Set ObjSubFolders = ObjFolder.SubFolders
For Each ObjFolder In ObjSubFolders
ObjOutFile.WriteLine("Folder," & ObjFolder.Name & "," & ObjFolder.Path)
GetFiles(ObjFolder.Path)
Next
End Function
I am getting Output as _OutputFiles.csv
If I run the script in a folder I want the output as
New Folder (3)_OutputFiles.csv
New Folder (2)_OutputFiles.csv
with all files listed.
Please suggest how to implement such that I get output for each parent folder separately.
You have to move your definition of the output file AFTER you obtain the parent folder name, and include the .Name attribute of the folder.
Dim fso
Dim ObjOutFile
Set fso = CreateObject("Scripting.FileSystemObject")
GetFiles("YOUR LOCATION")
ObjOutFile.Close
WScript.Echo("Completed")
Function GetFiles(FolderName)
On Error Resume Next
Dim ObjFolder
Dim ObjSubFolders
Dim ObjSubFolder
Dim ObjFiles
Dim ObjFile
Set ObjFolder = fso.GetFolder(FolderName)
Set ObjOutFile = fso.CreateTextFile(GetFiles(FolderName.Name) & "_"&"OutputFiles.csv")
ObjOutFile.WriteLine("Type,File Name,File Path")
Set ObjFiles = ObjFolder.Files
For Each ObjFile In ObjFiles
ObjOutFile.WriteLine("File," & ObjFile.Name & "," & ObjFile.Path)
Next
Set ObjSubFolders = ObjFolder.SubFolders
For Each ObjFolder In ObjSubFolders
ObjOutFile.WriteLine("Folder," & ObjFolder.Name & "," & ObjFolder.Path)
GetFiles(ObjFolder.Path)
Next
End Function

How do I automate folder location and file name in Access VBA?

I want to substitute the hard codes between the 2 underlined area in VB as indicated, so that it fetches the excel file automatically with code and transfers the spreadsheet into an Ms-Access table with same fields. IT should be able to do this function automatically with vb codes in MS-Access.
Dim fso As Object 'FileSystemObject
Dim f As Object 'File
Dim strTempPath As String
Dim objExcel As Object 'Excel.Application
Dim objWorkbook As Object 'Excel.Workbook
Const TemporaryFolder = 2
On Error Resume Next
StrSQL = "DELETE * FROM bed_code_tbl"
DoCmd.SetWarnings False
DoCmd.RunSQL StrSQL
Set fso = CreateObject("Scripting.FileSystemObject") 'New FileSystemObject
strTempPath = fso.GetSpecialFolder(TemporaryFolder) & "\" & fso.GetTempName & "\"
fso.CreateFolder strTempPath
'------------------------------------------------------
Set f = fso.GetFile("C:\Users\johnpfe\Documents\Bed_code_tbl.xlsx")
fso.CopyFile f.Path, strTempPath & f.Name
'--------------------------------------------------------
Set objExcel = CreateObject("Excel.Application") ' New Excel.Application
Set objWorkbook = objExcel.Workbooks.Open(strTempPath & f.Name)
objWorkbook.ActiveSheet.Range("A1:C100").Select
objWorkbook.Save
Set objWorkbook = Nothing
objExcel.Quit
Set objExcel = Nothing
DoCmd.TransferSpreadsheet acImport, acSpreadsheetTypeExcel9, "bed_code_tbl",
strTempPath & f.Name, True
fso.DeleteFile strTempPath & f.Name
fso.DeleteFolder Left(strTempPath, Len(strTempPath) - 1)
Set f = Nothing
Set fso = Nothing
End Sub
'----------------------------------------------------------------------
I'm assuming that you're trying to find the current user's documents folder.
You can use the eviron() function. More on that if you follow these links.
http://msdn.microsoft.com/en-us/library/office/gg264486(v=office.15).aspx
http://www.tek-tips.com/faqs.cfm?fid=4296
Dim fso As Object 'FileSystemObject
Dim f As Object 'File
Dim strTempPath As String
Dim objExcel As Object 'Excel.Application
Dim objWorkbook As Object 'Excel.Workbook
Const TemporaryFolder = 2
On Error Resume Next
strSQL = "DELETE * FROM bed_code_tbl"
DoCmd.SetWarnings False
DoCmd.RunSQL strSQL
Set fso = CreateObject("Scripting.FileSystemObject") 'New FileSystemObject
strTempPath = fso.GetSpecialFolder(TemporaryFolder) & "\" & fso.GetTempName & "\"
fso.CreateFolder strTempPath
'------------------------------------------------------
Set f = fso.GetFile(Environ("UserProfile") & "\Documents\Bed_code_tbl.xlsx")
fso.CopyFile f.Path, strTempPath & f.NAME
'----------------------------------------------------------------------
You can get folder location for Your access file. And place created file relative to that location.
Alternatively ask user for the location.

Keeping multiple file names while importing via transfertext

Private Sub Command38_Click()
Dim f As Object
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim strUpdate As String
Dim strFile As String
Dim strFolder As String
Dim varItem As Variant
Dim P As String
Dim DeleteEverything As String
DoCmd.SetWarnings False
DeleteEverything = "DELETE * FROM [ucppltr]"
DoCmd.RunSQL DeleteEverything
Set f = Application.FileDialog(3)
f.AllowMultiSelect = True
f.InitialFileName = "S:\Formware\outfile\ucppt12\Storage"
f.Filters.Clear
f.Filters.Add " Armored TXT Files", "*.asc"
If f.Show Then
For Each varItem In f.SelectedItems
strFile = Dir(varItem)
strFolder = Left(varItem, Len(varItem) - Len(strFile))
P = strFolder & strFile
DoCmd.TransferText acImportDelim, "UCPP Import Specification", "ucppltr", P, False
Next
End If
strUpdate = "PARAMETERS fileName Text;" & vbCrLf & _
"UPDATE ucppltr" & vbCrLf & _
"Set [File Name] = fileName"
Debug.Print strUpdate
Set db = CurrentDb
Set qdf = db.CreateQueryDef("", strUpdate)
qdf.Parameters("fileName") = strFile
qdf.Execute dbFailOnError
Set qdf = Nothing
Set db = Nothing
Set f = Nothing
MsgBox DCount("*", "ucppltr") & " Records were imported"
End Sub
As you can see from the code on import I want to store the file name and while it does work it doesn't work exactly how I need it to. When we do work for this client it is 5 files ate a time once a week so I would like it to save all 5 file names however it only saves the last one it imports. My question, is there a way to save each file name to each one ( I doubt that) or can I save all 5 file names to all the records I import instead of just the last file name?
I always have the option of only allowing a single import and making them import and append the table 5 times I just wanted to check to see if there is a more efficent way before doing so.
Thanks in advance for any help in this matter!
There is a problem in your logic. Inside the loop, strFile holds the current file name. So after your loop is finished, only the current (=last) file name is passed on to the query.
I made some changes, so the filenames are now stored in the new variable strFileList, delimited by a ";". Please check, if this is a feasible solution.
Private Sub Command38_Click()
Dim f As Object
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim strUpdate As String
Dim strFile As String
Dim strFolder As String
Dim varItem As Variant
Dim P As String
Dim DeleteEverything As String
' Variable to hold file list
Dim strFileList As String
DoCmd.SetWarnings False
DeleteEverything = "DELETE * FROM [ucppltr]"
DoCmd.RunSQL DeleteEverything
Set f = Application.FileDialog(3)
f.AllowMultiSelect = True
f.InitialFileName = "S:\Formware\outfile\ucppt12\Storage"
f.Filters.Clear
f.Filters.Add " Armored TXT Files", "*.asc"
If f.Show Then
For Each varItem In f.SelectedItems
strFile = Dir(varItem)
strFolder = Left(varItem, Len(varItem) - Len(strFile))
P = strFolder & strFile
DoCmd.TransferText acImportDelim, "UCPP Import Specification", "ucppltr", P, False
'Add file name to file list
strFileList = strFileList & strFile & ";"
Next
End If
strUpdate = "PARAMETERS fileName Text;" & vbCrLf & _
"UPDATE ucppltr" & vbCrLf & _
"Set [File Name] = fileName"
Debug.Print strUpdate
Set db = CurrentDb
Set qdf = db.CreateQueryDef("", strUpdate)
'Pass file list to query
qdf.Parameters("fileName") = strFileList
qdf.Execute dbFailOnError
Set qdf = Nothing
Set db = Nothing
Set f = Nothing
MsgBox DCount("*", "ucppltr") & " Records were imported"
End Sub