VBA Create folder and move file based on folder names in table - excel

I have around 10,000 files all in one folder called "Z:\ContactLog\". The files are named "Contact_1.pdf", "Contact_2.pdf" etc. I also have an Access table with the file names listed in the first column and an associated group name in the second column. The group names are "Group1", Group2" etc.
I need help to write the VBA code to create a sub-folder for each group using the group name as the folder name, (e.g. "Z:\ContactLog\Group1\") and then move the files into the folders according to the group names listed against the file names in the table.
My research so far has found code for moving files based on the file name, but not based on a table field entry. Any help to get started with writing the VBA would be greatly appreciated. I am using Access 2010, but will do this in Excel if needed. Thank you.

I hope it isn't considered bad form to answer your own question, but I have just thought of and tested an answer using a completely different approach.
To achieve the goal I did the following:
Export the access table to Excel, so column A has the file name and column B has the name of the desired destination folder.
In column C use the formula...
=CONCATENATE("xcopy Z:\ContactLog\",A1,".pdf Z:\ContactLog\",B1,"\ /C")
Copy the formula downwards for all 10,000 entries
Copy and paste column C into a batch file
Run the batch file
Manually delete the source files
I have tried this on a small sample of the entries and it works perfectly. Xcopy will create the folders that don't exist. The switch "/C" will allow the batch to continue if there is an error (e.g. if the file does not exist).

Looks like your set, but I thought I would add an Access answer for the heck of it.
First back up the entire folder in question so you can revert incase something goes wrong. Next add a column in the file information table called FILE_MOVED so you can use it as a flag.
I've done this sort of thing a lot and have run into many issues like files moved, renamed, locked, etc. (If there's an error in the run, you'll end up with more errors on subsequent runs trying to move file's that have already been moved.) Be sure to update the FILE_MOVED col to 0 or null if you have to revert to original folder. So here's some code that should accomplish what you wanted:
Declare this in a Module:
Declare Function MoveFile Lib "kernel32" Alias "MoveFileA" (ByVal lpExistingFileName As String, ByVal lpNewFileName As String) As Long
Paste this into a Module:
Function OrganizeFiles() As Long
On Error GoTo ErrHandler
Dim rst As New ADODB.Recordset
Dim strFolderFrom As String, strFolderTo As String
Dim strPathFrom As String, strPathTo As String
rst.CursorLocation = adUseClient
rst.CursorType = adOpenForwardOnly
rst.LockType = adLockOptimistic
rst.Open "SELECT * FROM [YourTableName] WHERE nz(FILE_MOVED,0) = 0 ", CurrentProject.Connection
strFolderFrom = "Z:\ContactLog\" 'the main folder will always be the same
Do Until rst.EOF
'destination folder
strFolderTo = strFolderFrom & rst.Fields("[YourGroupCol]") & "\" 'destination folder can change
'make sure the destination folder is there; if not, then create it
If Dir(strFolderTo, vbDirectory) = "" Then MkDir strFolderTo
'get the source file path
strPathFrom = strBaseFolder & rst.Fields("[YourFileNameCol]")
'get the destination file path
strPathTo = strFolderTo & rst.Fields("[YourFileNameCol]")
Call MoveFile(strPathFrom, strPathTo)
'at this point the file should have been moved, so update the flag
rst.Fields("FILE_MOVED") = 1
rst.MoveNext
Loop
rst.Close
ErrHandler:
Set rst = Nothing
If err.Number <> 0 Then
MsgBox err.Description, vbExclamation, "Error " & err.Number
End If
End Function
This task and the my code is pretty basic but this kind of thing can become complicated when working with multiple source and destination folders or changing file names in addition to moving them.

Related

Excel 2010 Macro - Creating txt files with names from ColA and content ColB. Stacko. solutions not work

I have found some answers/examples here on stackoverflow for an issue where in Microsoft Excell 2010, I want to create a txt files for each cell from for e.g. ColumnA which would contain file names, and ColumnB which would contain what is inside certain text file, however one example doesn't work at all, and second bugs after few files created.
You can use the CreateTextFile method which will create your file and provide a TextStream object which you can use to write to the text files. Microsoft Docs
Here's a code example that will do what you asked.
Sub CreateTxt()
Dim my_range As Range
Dim pth As String
Set my_range = Selection
For Each x In my_range.Rows:
pth = "C:\excel_test\" + x.Cells(1) + ".txt" 'file name in column A
Set file_sys = CreateObject("Scripting.FileSystemObject")
Set txt_file = file_sys.CreateTextFile(pth, True)
txt_file.WriteLine (x.Cells(2)) 'content in Column B
txt_file.Close
Next x
End Sub
Just remember, in order to create a file you need adequate permissions on the path you're writing to - I had to run excel as administrator to get the functionality.
Also, the True value in the CreateTextFile method is necessary to overwrite any files with the existing file name, if set to false it will throw an error when trying to write to the file.

How to know numerically the last saved file name

I am creating and saving .ini files in Excel. The files need to follow a specific naming convention that increments by 1 each time a file is created. Not all the files will be created in Excel, some will be done in a separate program. Is there a way to read the saved files in their folder to know which number is next?
For example there are files named exampleFile1.ini through exampleFile63.ini. From Excel using VBA or other means can I see that exampleFile63.ini was the last file and name the next exampleFile64.ini?
Thank you. I'm very new if thats not obvious.
This function will return the next available .INI file name:
Private Function GetNextFile() As String
Dim i As Long
Dim fileName As String
For i = 1 To 1000
' Update Path and File Name prefix below to where your .INI files will be stored.
fileName = "d:\path\exampleFile" & i & ".ini"
If Dir(fileName) = "" Then
GetNextFile = fileName
Exit Function
End If
Next
End Function
Call it like this:
Dim NextIniFile As String
NextIniFile = GetNextFile()

How to avoid select file window when refreshing link

I have a problem with a select file window popping up while updating a link to an excel file. I believe it's caused by the destination file being saved at the moment I refresh the link.
I have 2 computers. I open file "A" on the first one and file "B" on the other.
File "A" runs this macro:
application.enableevents = false
Do until(I set loop for couple minutes )
Range("a1").value = 1
save
range("a1).value = 2
save
Loop
File B runs this macro:
range("b2").value = (link to File A, cell "a1")
z = 1
do until (runs for couple minutes)
Cells(z,1).value = range("b2").value
z = z+1
loop
So basically the first file continuously changes the value of cell "a1" between 1 and 2, and saves each time, while the second one constantly refreshes the link and records the linked cell value.
It works for a few rounds, then a select file window pops up.
Exact formula for the cell containing link:
"='[" & BAZAO.Name & "]" & "ZMIANY'" & "!a1"
And in excel cell it looks like that:
„='[BWP 215.xlsm]ZMIANY'!a1”
The line of code that refreshes the link:
BAZA.UpdateLink (BAZAZ.Range("C3").Value)
BAZA - name of FILE B
BAZAZ.range("c3").value - contains address and name of file A
Range("b2").value = "='[" & BAZAO.Name & "]" & "ZMIANY'" & "!a1"
„='[BWP 215.xlsm]ZMIANY'!a1”
Can anyone tell me how to suppress this select file window, or if there is any other workaround?
I think it's happening because when opening the excel file, excel creates it's copy with generated name. When changes are being saved and the original file replaced, excel deletes original file first, and then puts a temporary file in its place changing name to the original one.
I guess the select file window pops up when my macros hit between that moments.
Is this the cause?
I think I have found a workaround.
Instead of using a cell to track file avaliability I have made the code to create file "inuse.txt" in the "file A" directory whenever its in use.
Then the "file B" just checks if that file is present through dir command

Removing log files except for the most recent 5 using Excel VBA

My Excel VBA worksheet creates logs in a directory. Currently, the logs keep building up as I do not remove them.
However, now I would like to only keep the most recent 5. My logs are created with filenames as below:
<worksheet_name>_YYYYMMDD_HH_MM_SS.log
My current method of doing this job is to throw these logs into an array, sort the array, and keep only the first 5.
My question is this: Does anyone have a better method of keeping only the most 5 recent log files?
That sounds like a workable solution. Use the FileSystemObject library to gather all the log files, then loop thru them.
One option: you could try deleting based on Date Created or Date Modified, i.e. if the file was created over x days ago, delete it.
Also, I don't know how important these files are, but you may want to just move them to a folder called Archive instead of outright deleting them.
One system we used a while ago was to keep e.g. 5 log files with a "gap". So you would create the first 5 log files:
Files: 1,2,3,4,5
Then, on the 6th day, your gap is at 6, so create 6 and delete 1
Files: ,2,3,4,5,6
The gap is now at 1. So for the next day, create 1, and delete 2
Files: 1, ,3,4,5,6
The gap is now at 2. So for the next day, create 2, and delete 3
Files: 1,2, ,4,5,6
etc etc
i.e. "Find the Gap" *, fill it with the new file, then delete the one after it.
Just an idea.
_* (yes this is a bad joke referring to the London Underground)
Even though this is an old question, since I needed this exact solution I figured I would add it here. This code assumes that the file name ends in something that is sortable by string comparison, so that could be files of a format SomeName_YYYY-MM-DD. Twenty-four hour time stamps can be incorporated as well. This process does not rename any files, so any incremental numeric scheme will need to be carefully managed by other code (i.e. you want to add _1, _2, etc. to the file names).
Note that this solution leverages collections which serve this purpose much better than an array.
Public Sub CleanBackups(filePathAndBaseName As String, fileExtension As String, maxCopiesToKeep As Integer)
'
' Calling Example
' CleanBackups "C:\Temp\MyLog", ".txt", 5
'
' The above example would keep only the 5 versions of the file pattern "C:\Temp\MyLog*.txt"
' that are "LARGEST" in terms of a string comparison.
' So if MyLog_1.txt thru MyLog_9.txt exist, it will delete MyLog_1.txt - MyLog_4.txt
' and leave MyLog_5.txt - MyLog_9.txt
' Highly recommend using pattern MyLog_{YYYY-MM-DD_HhNn}.txt
Dim pathOnly As String
Dim foundFileName As String
Dim oldestFileIndex As Integer
Dim iLoop As Integer
Dim fileNameCollection As New Collection
pathOnly = Left(filePathAndBaseName, InStrRev(filePathAndBaseName, "\"))
foundFileName = Dir(filePathAndBaseName & "*" & fileExtension, vbNormal)
Do While foundFileName <> ""
fileNameCollection.Add foundFileName
foundFileName = Dir
Loop
Do While fileNameCollection.Count > maxCopiesToKeep
' Find oldest file, using only the name which assumes it ends with YYYY-MM-DD and optionally a 24-hour time stamp
oldestFileIndex = 1
For iLoop = 2 To fileNameCollection.Count
If StrComp(fileNameCollection.Item(iLoop), fileNameCollection.Item(oldestFileIndex), vbTextCompare) < 0 Then
oldestFileIndex = iLoop
End If
Next iLoop
Kill pathOnly & "\" & fileNameCollection.Item(oldestFileIndex)
fileNameCollection.Remove oldestFileIndex
Loop
End Sub

Here is some Applescript code to interact with Microsoft Excel on Snow Leopard - How to add the missing functions

I have about 400 excel files. I want to insert a column just before the first column in the existing file and then insert the name of the file into each row of that column.
I know a little bit of Applescript and based on that I wrote this script so that I can drop some files onto the script and it will execute the script on each one of those files.
I was wondering if someone could help me in completing the "TO DO" lines. Upon execution this script gives me dialogue boxes with the path of files that I drop on top. But the excel application throws an error dialogue box which says" Not enough memory". I tried this with only 2 excel files so it wasn't the number of files that caused the error.
Can someone please give me a hand with completing the TODO lines and give me an ide as to why Im getting the error. Thanks
property numFiles : 0
on open excelFiles
set fileNames to ""
tell application "Finder"
repeat with eachFile in excelFiles
--open document file eachFile
--tell application "Microsoft Excel"
--increment count
--save name of each file
set fileNames to fileNames & return & (POSIX path of eachFile)
--TO DO insert a column
--TO DO insert text in each column to the name of eachFile
--end tell
end repeat
display dialog fileNames
--display dialog "Ouch that hurt " & return & "You dropped " & (count excelFiles) & "files on me"
end tell
end open
on addFilePath(eachFile)
set fileNames to fileNames & (POSIX path of eachFile)
end addFilePath
Thanks a lot
I don't understand everything --> insert the name of the file into each row of that column | TO DO insert text in each column to the name of eachFile.
Here is the script, Updated :
on open excelFiles
set numFiles to count excelFiles
repeat with eachFile in excelFiles -- open each file in Excel
tell application "Microsoft Excel"
set tBook to open workbook workbook file name (eachFile as string)
set tName to name of tBook
insert into range column 1 of active sheet -- insert column
set lastCell to last cell of used range of active sheet -- get last cell from the used range
set value of range ("A1:A" & first row index of lastCell) of active sheet to tName --set first column's values to the file name
close tBook saving yes
end tell
end repeat
display dialog numFiles
end open
Edit : I forgot the error :
Not enough memory : This weird error seems to be : you call a handler without using my or tell me to) in a tell block application.
Use my like this : set x to my addFilePath(eachFile)
Also, a tell application "Microsoft Excel" block in the application Finder block is not recommended, this can cause unexpected errors.

Resources