Adding multiple attachments from a folder
Rob Cooper recently made a post, Adding Attachments from a Folder, which shows how to add a single attachment file per row. But what if you wanted to add more than one file? One (highly contrived) scenario would be to add all of the files in a folder to one row, and do so recursively if requested, similar to Rob's example.
What follows is some VBA code to do this, which borrows a bit from Rob's post and a bit from one of my earlier posts. However, I should point out this (again, highly contrived scenario) is meant only as an example and not something I would recommend doing, because if you are adding more than just a few files you can (ok, WILL) bloat your database very quickly, and in doing so can negatively impact performance and potentially hit the two gigabyte file size limit very quickly (see Access 2007 Specifications for details on database file size and object limitations).
First, to use the following sample code you will need to do some setup. Create a new table, add the following fields, and save it as Table1:
Table1
| Field Name |
Data Type |
| ID |
Autonumber (Primary Key) |
| FolderPath |
Text |
| Files |
Attachment |
Next, open the VBE window (ALT+F11) and insert a new module (Insert -> Module), and paste in the following code:
' -------------------------------------------------------------------------
' Procedure : StoreFilesInTable
' Purpose : Adds all files matching the specified file mask from the
' : specified folder to an attachment field.
' : Each row in the represents all files stored from the folder.
' Arguments : strFolder - The path to the folder stored in the attachment field.
' : strTable - The name of the table containing the attachment field.
' : strPathField - The name of the field for the archived folder.
' : strAttachmentField - The name of the attachment field. [Files]
' : strPattern - File mask. [*.*]
' : blnIncludeSubfolders - Recurse into subfolders. [False]
' : db1 - The database to operate on. [CurrentDb]
' Comments : The db1 param is included so this can be used to store files in
' : a separate database, since using the attachment field this way
' : can quickly push a database beyond the 2gb file size limit.
' -------------------------------------------------------------------------
Public Function StoreFilesInTable( _
ByVal strFolder As String, _
ByVal strTable As String, _
ByVal strPathField As String, _
Optional ByVal strAttachmentField As String = "Files", _
Optional ByVal strPattern As String = "*.*", _
Optional ByVal blnIncludeSubfolders As Boolean = False, _
Optional ByRef db1 As DAO.Database)
Const CALLER = "StoreFilesInTable"
On Error GoTo StoreFilesInTable_ErrorHandler
Dim strFilePath As String
Dim rstParent As DAO.Recordset2
Dim rstChild As DAO.Recordset2
Dim fldAttach As DAO.Field2
' These objects require a reference to the "Microsoft Scripting Runtime"
' but are defined as "Object" instead to use late binding and avoid that.
' If you've added the reference, remove the "Object" and uncomment the
' following lines to get the intellisense autocomplete for these objects.
Dim objFso As Object ' Scripting.FileSystemObject
Dim objFolder As Object ' Scripting.Folder
Dim objSubFolder As Object ' Scripting.Folder
Dim objFile As Object ' Scripting.File
' If the user did not specify a database, use the current one.
If db1 Is Nothing Then Set db1 = Application.CurrentDb
' Instantiate the FileSystemObject.
Set objFso = CreateObject("Scripting.FileSystemObject")
' Make sure the folder path always ends with a "\".
If (Right(strFolder, 1) <> "\") Then strFolder = strFolder & "\"
' Make sure the folder exists.
If Not objFso.FolderExists(strFolder) Then
MsgBox "Folder does not exist: " & strFolder, _
vbExclamation, CALLER
Exit Function
End If
' It exists, so get the folder object.
Set objFolder = objFso.GetFolder(strFolder)
' Open the table containing the attachment field
Set rstParent = db1.OpenRecordset(strTable)
rstParent.AddNew
rstParent.Fields(strPathField).Value = objFolder.Path
' Get the first file in this directory.
strFilePath = Dir(strFolder & strPattern)
' Store each file that meets the pattern
While (Len(strFilePath) > 0)
Set rstChild = rstParent.Fields(strAttachmentField).Value
rstChild.AddNew
Set fldAttach = rstChild.Fields("FileData")
fldAttach.LoadFromFile strFolder & strFilePath
rstChild.Update
rstChild.Close
strFilePath = Dir() ' Get the next file
Wend
' Commit the new row with the attachments field populated
' with all of the files from the current folder.
rstParent.Update
' Recurse into subfolders if requested.
If (blnIncludeSubfolders) Then
For Each objSubFolder In objFolder.SubFolders
StoreFilesInTable objSubFolder.Path, strTable, _
strPathField, strAttachmentField, _
strPattern, blnIncludeSubfolders, db1
Next
End If
Cleanup:
rstParent.Close
Set rstParent = Nothing
Exit Function
StoreFilesInTable_ErrorHandler:
Debug.Print "Error # " & Err.Number & " in " & CALLER & " : " & Err.Description
MsgBox Err.Description, vbCritical, "Error # " & Err.Number & " in " & CALLER
GoTo Cleanup
End Function 'StoreFilesInTable
Here is a short routine to help you test the above code. You will need to change the "<YourUserName>" to your login name, or just change the whole path in the strRootFolder string constant to the folder you want to store in the table. Note that I've set the blnIncludeSubfolders parameter to False to keep you from inadvertently bloating your database, but you can set it to True if you want to include all of the subfolders, too.
Sub TestStoreFilesInTable()
Const strRootFolder As String = "C:\Users\<YourUserName>\Pictures\"
StoreFilesInTable strRootFolder, "Table1", "FolderPath", "Files", "*.jpg", False
MsgBox "Done adding files from: " & vbCrLf & strRootFolder & "*.jpg", _
VbMsgBoxStyle.vbInformation, "TestStoreFilesInTable"
End Sub
I’m a Software Design Engineer in Test II (a.k.a. SDET II) on the Access team. I’ve been at Microsoft for over 11 years, and I've worked on many different teams, mostly in Office. I started working on Schedule+ in the Exchange server team, then I moved to Outlook for 98/2000, Office Programmability for Office XP, Excel for Office 2003, and finally the Access team for Office 2007 where I still work today. For Access 2007, I worked on the new complex data types (fields that allow multiple values) such as the new Attachment data type, and I owned the testing of DAO for the privatized version of JET called the Access database engine. More recently I worked on the Package Solution Wizard in the new Access Developer Extensions.
I’m passionate about programming--particularly when it comes to programming in Office applications such as Access 2007, or Excel. I wrote the Excel 2003 XML Tools Add-in Version 1.1 (which can be found at "http://msdn2.microsoft.com/en-us/library/Aa203739(office.11).aspx"). When I'm not programming in Access, I enjoy spending time with friends, working in the yard, watching movies, traveling, playing billiards, ultimate Frisbee, softball, golf, guitar, and probably way too much Halo on my Xbox 360.