How I Exported an Attachment fields data to a folder (1 Viewer)

chuckcoleman

Registered User.
Local time
Yesterday, 22:01
Joined
Aug 20, 2010
Messages
363
I built an Access 2010 database about two years ago for a client. My client wanted to scan customer contracts and save them with the database. I knew there were two methods; save the scanned documents in an Attachment file or save just the path to the file as a Hyperlink. At the time, (maybe I didn’t do enough research), I decided to use the Attachment file method. I probably also underestimated the quantity of scanned documents the customer would have and the impact on the database file size. From the start, the database was split into a Front End and a Back End. At inception, the Back End was about 3MB in size. Today, it is over 660MB in size and growing with every scanned document.


I started doing research online to figure out how I could export all of the scanned documents from the Attachment field, save them to a folder, and then add their location to a new table and field so the customer could still access them. It’s important to note that each scanned contract is associated with a customer order and I would need to ensure that whenever my customer went to a customer’s order, they would see only those scanned contracts. I never found in one place a “How To Export Attachments” article so I decided to summarize here what I did in the hope that it helps others that need to reverse stored documents/pictures/etc. from an Attachment field and save them in a folder. Maintaining the relationship to the location in the database are now being saved was critical.


Before you begin, make sure you back up your Back End data as well as your Front End. Also, please hold the feedback on how I named my fields and/or tables. I’m comfortable with it and it works for me. Yes, I know sometimes I need to use brackets on my field/table names.


One sample code that I used was from the Microsoft Access 2010 Programmer’s Reference manual. I modified the code slightly and it is shown below:


Public Function SaveAttachmentsTest(strPath As String, Optional strPattern As String = "*.*") As Long
Dim dbs As DAO.Database
Dim rst As DAO.Recordset
Dim rsA As DAO.Recordset2
Dim rsB As String
Dim fld As DAO.Field2
Dim OrdID As DAO.Field2
Dim strFullPath As String

'Get the database, recordset, and attachment field
Set dbs = CurrentDb
Set rst = dbs.OpenRecordset("Order Table")
Set fld = rst("Scan")
Set OrdID = rst("OrderID")

'Navigate through the table
Do While Not rst.EOF

'Get the recordset for the Attachments field
Set rsA = fld.Value
rsB = OrdID.Value

'Save all attachments in the field
Do While Not rsA.EOF
If rsA("FileName") Like strPattern Then
'To Export the data, use the line below
strFullPath = strPath & "\" & rsA("FileName")

'Make sure the file does not exist and save
If Dir(strFullPath) = "" Then
rsA("FileData").SaveToFile strFullPath
End If

'Increment the number of files saved
SaveAttachmentsTest = SaveAttachmentsTest + 1
End If

'Next attachment
rsA.MoveNext
Loop
rsA.Close

'Next record
rst.MoveNext
Loop

rst.Close
dbs.Close

Set fld = Nothing
Set rsA = Nothing
Set rst = Nothing
Set dbs = Nothing
End Function


Some key points.
The table that contains the attachments field is [Order Table]. The field for each order is [OrderNbr]. The Attachment field’s name is [Scan]. My Attachment field when viewed in the Query By Entry, (QBE), shows:

· Scan.FileData
· Scan.FileName
· Scan.FileType

I created a temporary Form with two Command Buttons on it:

· Export Attachments
o This had a simple macro on the On Click event that was:
§ RunCode and the Function Name was: SaveAttachmentsTest(“R:\Attachments”) where “R:\Attachments” was the location of the folder where I was going to save the scanned contracts to. When the Function was executed, it exported each scanned document in the order they were input into the database to that folder. (Although I haven’t shown this, I modified the above code slightly to modify as the file name and show the [OrderNbr] just to be able to verify the order and the associations between the scanned contract file name and the [OrderID] were in the right order.)

· Run Append Query
o I created a new table that I called Attachments Table. It has three fields in it:
§ [AttachNbr] which is an AutoNumber field
§ [OrderID] which is a Number field that will correspond/establish the relationship back to the [OrderID] field in the [Order Table]
§ [FileN] which is a Hyperlink field to store the location where the file is saved
o The Append query used the following SQL:
INSERT INTO [Attachments Table] ( OrderID, FileN )
SELECT [Order Table].OrderID, [Scan].[FileName] & "#" & "R:\Attachments\" & [Scan].[FileName] & "#" AS FileN
FROM [Order Table] WHERE ((([Order Table].Scan.FileName) Is Not Null));

This Query appends to the [Attachments Table] the [OrderID] from the [Order Table], (to the [OrderID] field), and a string, “R:\Attachments\”, (see NOTE below), which is the folder location where I just exported the scanned contracts to, and concatenated to it is the file name from the [Scan].[FileName] part of the Attachments/[Scan] field. NOTE: In order to get the Hyperlink data to be correctly stored in the field, you must use the “#” symbols as show in the SQL string. A Hyperlink field contains three parts separated by pound signs “#”. The template is: Display Text # file name including the path # Any reference within the file, (i.e. a sheet name if you’re importing an Excel spreadsheet). I found a helpful reference to this at: http://allenbrowne.com/casu-09.html

I also found that in my VBA editor that I needed to go to Tools, References and check Microsoft Office 14.0 Object Library.

I then modified my Order Form to remove the Attachment field input/delete button and then added a new Command button to open up my new Attachment Form, (Default View: Continuous Forms). This form has a couple of events:


· On Open it goes to a new record
· On Before Insert it triggers a macro to SetValue of the [OrderID] field to equal the [OrderID] field of the Order Form where this form was opened from. This links the hyperlink location and file with the OrderID.
· The form is based on a Query that uses as its only source the Attachments Table. The three fields from the Attachment Table are used in the query and the [OrderID] field has criteria that equals Forms![Customer Order Form]![OrderID] to make sure that only records for the customer in the form are shown. The form also has two Command buttons:

o Attach: It uses this code:
Private Sub cmdPopulateHyperlink_Click()
'First, set a Reference to the Microsoft Office XX.X Object Library

Dim strButtonCaption As String, strDialogTitle As String
Dim strHyperlinkFile As String, strSelectedFile As String

'Define your own Captions if necessary
strButtonCaption = "Save Hyperlink"
strDialogTitle = "Select File to Create Hyperlink to"

With Application.FileDialog(msoFileDialogFilePicker)
With .Filters
.Clear
.Add "All Files", "*.*" 'Allow ALL File types
'Test line so I can debug/compile the code
End With
'The Show Method returns True if 1 or more files are selected
.AllowMultiSelect = False 'Critical Line
.FilterIndex = 1 'Database files
.ButtonName = strButtonCaption
.InitialFileName = vbNullString
.InitialView = msoFileDialogViewDetails 'Detailed View
.Title = strDialogTitle
If .Show Then
For Each varItem In .SelectedItems 'There will only be 1
'Display Text + # + Address of Hyperlink (Display Text#Hyperlink Address)
strSelectedFile = varItem
strHyperlinkFile = fGetBaseFileName(strSelectedFile) & "#" & strSelectedFile
Me![FileLocX] = strHyperlinkFile
Next varItem
End If
End With
End Sub
o Delete: Simple Delete macro

Note: the above VBA code I found on a few different sites

I tested the functionality and once I was satisfied everything works, I deleted my [Scan] field from the [Order Table], compacted the database and went from 665MB to 4.6MB.


I hope this is helpful to all who need to reverse an internally stored attachment to saving it externally.


Chuck
 

dutch

New member
Local time
Today, 13:01
Joined
Dec 19, 2012
Messages
1
Hi,

Would there be any chance of obtaining a copy of the db file?

Regards,

Dutch
 

chuckcoleman

Registered User.
Local time
Yesterday, 22:01
Joined
Aug 20, 2010
Messages
363
Dutch, I can't provide the db. If you have some questions, I'll try to answer them for you.

Chuck
 

Clut

Registered User.
Local time
Today, 04:01
Joined
May 5, 2010
Messages
29
Chuck,

I'm about to start a project in which I could potentially end up in the same situation as you found yourself in.

The project will be split into a front end UI with a back-end data store located on a network drive, both being Access 2007.
As part of the data input, there are a couple of places where the user will be able to attach files such as word docs, excel sheets and images.

Do you have any suggestions on what the best practice for this would be? Storing the attachements directly on the backend, or linking to the files that would need to manually moved to a common location on the network drive? Is there a way to make the 'manual file move' easier for the users? Could you possibly share any wisdom on this?

Many many thanks
 

chuckcoleman

Registered User.
Local time
Yesterday, 22:01
Joined
Aug 20, 2010
Messages
363
Clut, my experience was that I built a database, FE & BE, and stored the attachments directly within a table. The attachments were jpg "pictures" of scanned contracts. Within about 9 months, the database BE grew from 8 MB to over 100 MB. This was going to get out of control. That's why I found and modified the solution that I posted to reverse the process. Therefore, I WOULD NOT store the actual attachment but I would store the Hyperlink to where the attachment is. A year after storing only the Hyperlink, the database size is hardly 10 MB. I found this solution on the web which I used in my solution.

http://bytes.com/topic/access/insights/741095-how-programmatically-create-hyperlink-form

That's the code behind a new form that is opened from the customer order form and on the new form the code is behind a command button named, "Attach" which allows the user to navigate to where the file is stored so the location is captured. I had my client store all Hyperlink file location on a share folder on the network which is mapped the same way on all users computers so the Hyperlink will open the file from any computer.

I hope this helps!

Take care,

Chuck
 

Clut

Registered User.
Local time
Today, 04:01
Joined
May 5, 2010
Messages
29
Chuck,

Thanks for your reply. I think you've definitely saved me some headaches by steering me away form storing the actual attachments directly on the database.

I do have one question regarding your last reply, if you'd be so kind as to clarify something further after already helping out.
Where you say 'I had my client store all Hyperlink file location on a share folder on the network...' Does that mean the client automatically moved all files to the network drive before saving their path, or were users expected to move the files to the network drive manually before attaching them?

Thanks again
Clut
 

chuckcoleman

Registered User.
Local time
Yesterday, 22:01
Joined
Aug 20, 2010
Messages
363
Clut, I have two clients that use this. In both cases they scan signed contracts and drawings using a scanner. As a part of scanning the contract/drawing, they are asked for a file name and a location to save it. They give it a file name and save it to a shared folder on the network. That folder is accessible by anyone in the group. Then the swing over to the Access application and go to the Customer Form and the customer that just signed the contract, open the Attach form, click on the Attach button which gives them a standard Windows file navigation dialog box, navigate to the file location, click on it and it's saved. WOW! They understand if someone manually moves the file, the link is broken. Hope this helps.

Chuck
 

Clut

Registered User.
Local time
Today, 04:01
Joined
May 5, 2010
Messages
29
Chuck

Thanks again for your reply. It is now all clear. I am going to look into having Access automatically move the attachments onto the network drive before saving the link as I think my users will be attaching files from their local machines and I just know that they won't remember to move the files to the network drive every time before 'attaching' them.
 

XelaIrodavlas

Registered User.
Local time
Today, 04:01
Joined
Oct 26, 2012
Messages
174
Hi Chuck,

This is fantastic thank you for writing in so much depth. I have some questions though so I hope you still check in online :)

My trouble is with the export code, how do I tell it where to save the files to?

Here's the code I copied off you, highlighted where I changed to my own tables/fields - i think that's all i needed to change...

Code:
Public Function SaveAttachmentsTest(strPath As String, Optional strPattern As String = "*.*") As Long
Dim dbs As DAO.Database
Dim rst As DAO.Recordset
Dim rsA As DAO.Recordset2
Dim rsB As String
Dim fld As DAO.Field2
Dim OrdID As DAO.Field2
Dim strFullPath As String

'Get the database, recordset, and attachment field
Set dbs = CurrentDb
Set rst = dbs.OpenRecordset("[COLOR="red"]TBL Employee Details[/COLOR]")
Set fld = rst("[COLOR="red"]Documentation[/COLOR]")
Set OrdID = rst("[COLOR="red"]EmpDetID[/COLOR]")

'Navigate through the table
Do While Not rst.EOF

'Get the recordset for the Attachments field
Set rsA = fld.Value
rsB = OrdID.Value

'Save all attachments in the field
Do While Not rsA.EOF
If rsA("FileName") Like strPattern Then
'To Export the data, use the line below
strFullPath = strPath & "\" & rsA("FileName")

'Make sure the file does not exist and save
If Dir(strFullPath) = "" Then
rsA("FileData").SaveToFile strFullPath
End If

'Increment the number of files saved
SaveAttachmentsTest = SaveAttachmentsTest + 1
End If

'Next attachment
rsA.MoveNext
Loop
rsA.Close

'Next record
rst.MoveNext
Loop

rst.Close
dbs.Close

Set fld = Nothing
Set rsA = Nothing
Set rst = Nothing
Set dbs = Nothing
End Function

I saved this as a separate module and titled it SaveAttachmentsTest, is this right? the problem is in the next step, i made the form with the button with the macro to run the code with function name 'SaveAttachmentsTest(C:\Users\alexsalvadori\Desktop\Attachments)'. However when I click the button I get an error 2425 saying the expression entered has a function name access can't find. Should I rename the module to match this name? because I tried that and it exceeded the 64 character limit! D:

EDIT: I replaced all instances of SaveAttachmentTest with the letters SAT to shorten the string, but still the same error message. what am i doing wrong?

please help :) thank you
 
Last edited:

chuckcoleman

Registered User.
Local time
Yesterday, 22:01
Joined
Aug 20, 2010
Messages
363
Alex, I'll be glad to help. Unfortunately, I'm traveling until Thursday. On Thursday I'll get back to you with a better answer to your question.

Take care,

Chuck
 

gypsy_chiclet

New member
Local time
Yesterday, 21:01
Joined
Jan 9, 2014
Messages
1
i realize this is an older thread, but thank you for this! i have the same problem and i copied your code for the export pretty much directly and it works! i was even able to figure out how to append the id number to the exported file name.
i'm saving the "re-linking" process for tomorrow when i have a fresh brain, but i wanted to say thanks for the clear explanation. yours was the best i found out there.
cheers!:)
 

chuckcoleman

Registered User.
Local time
Yesterday, 22:01
Joined
Aug 20, 2010
Messages
363
Gypsy_chicklet,

Thank you very much for your feedback. It really made my day.

I'm glad it worked for you.

Thank you again,

Chuck
 

pmontalto

New member
Local time
Yesterday, 20:01
Joined
Feb 27, 2014
Messages
5
Hello Chuck. Thanks for posting this. I'm having some issues implementing this code however. I've followed your procedure so far and have my On Click to RunCode. as SaveAttachmentsTest("C:\Attachments") and I'm getting errors about invalid number of arguments. Then, I tried SaveAttachmentsTest("C:\Attachments","C:\Attachments") and it executes when I click my button, but nothing happens. Here is my code:

Code:
Public Function SaveAttachmentsTest(strPath As String, Optional strPattern As String = "*.*") As Long
Dim dbs As DAO.Database
Dim rst As DAO.Recordset
Dim rsA As DAO.Recordset2
Dim rsB As String
Dim fld As DAO.Field2
Dim OrdID As DAO.Field2
Dim strFullPath As String
 
'Get the database, recordset, and attachment field
Set dbs = CurrentDb
Set rst = dbs.OpenRecordset("[COLOR=red]Tasks[/COLOR]")
Set fld = rst("[COLOR=red]Attachments[/COLOR]")
Set OrdID = rst("[COLOR=red]ID[/COLOR]")
 
'Navigate through the table
Do While Not rst.EOF
'Get the recordset for the Attachments field
Set rsA = fld.Value
rsB = OrdID.Value
 
'Save all attachments in the field
Do While Not rsA.EOF
If rsA("FileName") Like strPattern Then
 
'To Export the data, use the line below
strFullPath = strPath & "\" & rsA("FileName")
 
'Make sure the file does not exist and save
If Dir(strFullPath) = "" Then
rsA("FileData").SaveToFile strFullPath
End If
 
'Increment the number of files saved
SaveAttachmentsTest = SaveAttachmentsTest + 1
End If
 
'Next attachment
rsA.MoveNext
Loop
rsA.Close
 
'Next record
rst.MoveNext
Loop
rst.Close
dbs.Close
 
Set fld = Nothing
Set rsA = Nothing
Set rst = Nothing
Set dbs = Nothing
 
End Function

Literally nothing happens. The button gets clicked and no files are saved. I have about a few hundred out of about 2000 Tasks that have 1-3 PDF files attached to them in a field called Attachments.

Please help. Thanks.
 

chuckcoleman

Registered User.
Local time
Yesterday, 22:01
Joined
Aug 20, 2010
Messages
363
Pmontalto, sorry for the delayed response. Unfortunately, because of my schedule I won't be able to look at your issue until sometime this weekend.

Chuck
 

chuckcoleman

Registered User.
Local time
Yesterday, 22:01
Joined
Aug 20, 2010
Messages
363
Pmontalto,

I looked at my "On Click" code for the button and it is: Run Code, Function Name, SaveAttachmentsTest("J:\") I can't remember for sure but I think I just mapped a new drive letter "J" as a temporary storage place.

Also, did you in the VBA editor go to Tools, References and add/check Microsoft Office 14.0 Object Library?

Hope this helps. The code has worked for others.

Chuck
 

pmontalto

New member
Local time
Yesterday, 20:01
Joined
Feb 27, 2014
Messages
5
Thanks Chuck for the reply. One more question - if I have multiple attachments in one Attachment field (i.e [Scan] field), what would the Append query have to be in order to export the filenames of all the attachments?

For example, right now if Task 3 has Task3.txt and Task3-2.txt, only Task3.txt will be copied over to the Attachments table under the FileN field.

Thanks!!
 

themurph2000

Fat, drunk, and stupid
Local time
Yesterday, 22:01
Joined
Sep 24, 2007
Messages
181
I just tried the code you had given us. I couldn't believe it when I got it to work on the very first try. I am definitely not an expert when it comes to Access. You may have just gotten me a job at this company permanently.

Excellent work and thank you very much for helping with a very difficult project.
 

chuckcoleman

Registered User.
Local time
Yesterday, 22:01
Joined
Aug 20, 2010
Messages
363
TheMurph2000,

Thank you for your kind words. I'm glad it all worked out for you; especially being able to keep your job. Does that mean that I'll now get Christmas cards from you every year?

Take care and all the best,

Chuck
 

nburleigh

New member
Local time
Yesterday, 23:01
Joined
Aug 10, 2016
Messages
2
Hi Chuck,

I'm late to the party here, but I want to say thank you for posting this! It has been amazingly helpful, as I'm trying to transition an attachment-heavy database that is reaching its capacity.

I'm having a little trouble executing the VBA code to export attachments. In my case, often a user has attached the exact same file to multiple records. It's not handling these duplicates well. Basically, any time the code tries to copy to a file that already exists, it throws an error and shuts down. The debugger stops me here:

Code:
rsA("FileData").SaveToFile strFullPath

The logic in the code makes complete sense to me; if the path doesn't exist, then copy the file. If it does exist, it would ignore the Then statement, end the If statement, and move on to the next attachment. But it's stopping me cold. Any thoughts? Would really appreciate it! Thanks!
 
Last edited:

chuckcoleman

Registered User.
Local time
Yesterday, 22:01
Joined
Aug 20, 2010
Messages
363
Hi, OH GREAT, you're asking me about some code I posted four years ago!

Just a guess buy why don't you look into some kind of a random number generator and if the file exists then concatenate a "-" and then the random number. It would then be unique.

Then, when you get them into a table it would be fairly easy to strip the "-" and anything to the right of it.

Just a thought.

Chuck
 

Users who are viewing this thread

Top Bottom