Create a list of files in current file for use later in code - excel

I have a file that is referencing 3 files outside of it. The problem is the outside files will have their version number changed when there is a change.
code is currently written to pull from C:documents/product_eval
01-Main_v1 is the main file that pulls
02-Address_v1
03_Products_v1
However, we now have a v2 for each of these files. I need a way to have file_03 always pull the 3rd file in the list of files, no matter what the version.
I feel like listing the code I tried will just confuse people, as it is so far off.
but here is the coding it will be feeding into
Sub LaunchBatching3_00(sourcePath As String, exportFolder As String, activeName As String)
Dim Adrs_PATH As String
Dim Prod_PATH As String
Adrs_PATH = Application.ActiveWorkbook.Path & "\02-Address_v1.xlms"
Prod_PATH = Application.ActiveWorkbook.Path & "\03-Products_v1.xlms"

Dim sFiles as Object, fFiles as Variant ,ppath as String, count as Long,
Set fFiles=CreateObject("Scripting.FileSystemObject")
set sFiles =fFiles.GetFolder(ppath)'get the folder object from folder path(variable ppath)
count=0
For Each x in sFiles.Files'loops all files in folder search for the last version by filename
If InStr(1,x.Name,"_v")>0 then
If CLng(Mid(x.Name,InStr(1,x.Name,"_v")+2,1))>count then count=CLng(Mid(x.Name,InStr(1,x.Name,"_v")+2,1))'gets the largest version
End If
Next x
For Each x in sFiles.Files
If CLng(Mid(x.Name,InStr(1,x.Name,"_v")+2,1)=If CLng(Mid(x.Name,InStr(1,x.Name,"_v")+2,1)=count then
'... fill your actions, for example,
Workbooks.Open FileName:=x.Name
End if
Next x

Related

Add 'sep=' line to the csv file

The problem is, I want to copy data from .csv file, but excel automatically separates it into columns by comma, I need to separate it by ";".Can I edit csv file using vba code to add 'sep=' at the beginning?
Excel/VBA ignores the separator option if the file has the .csv extension. You have to rename it to set the delimiter. Check out my VBA CSV parser project.
The solution worked for me is to use filesystem object to read csv file and copy it into temporary file with 'sep=' at the first line.
Here is the code:
Function readCsvF(delim as String, fPath as String) As String
Dim sourceFile As Object, objFSO as Object, newTempFile as Object, _
line as String, newName as String
Set objFSO = CreateObject("scripting.FileSystemObject")
Set sourceFile = objFSO.OpenTextFile(fPath)
newName = objFSO.GetParentFolderName(fPath) & "\tempCSVfile.csv"
Set newTempFile = objFSO.CreateTextFile(newName, True)
newTempFile.Writeline("sep=" & delim)
While Not sourceFile.AtEndOfStream
line = sourceFile.Readline
newTempFile.Writeline (line)
Wend
sourceFile.Close
newTempFile.Close
readCsvF = newName
End Function
So what this function does is basically creates new file in which writes first line sep=*'your specified delimiter'* and then copies data from original csv file line by line. This function takes two string parameters: delim is delimiter you want to use and fPath is a path to the csv file, - and returns a path to the new file, so you can open it as workbook and do whatever manipulation you want with it.
Hopefully this will help someone, I really struggled to find the solution, maybe there was any better way, idk.

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()

Determine Image in Excel Comment

I have found plenty of vba for inserting images into a comment
Selection.ShapeRange.Fill.UserPicture "C:\Temp\Pictures\ewe.jpg"
How can you determine the image already used for an comment?
I would like to extract the embedded image names if possible.
Is there not a property to access that will give me this?
In the comment Fill Effects dialog box the image name somehow seems to be accessible.
Sorry, I didn't have the reputation to just comment on your question for clarification.
I made a test file, inserted a comment and image in that comment, and then extracted the base files. I then checked them all for the original file name. I also found the embedded JPEG and decoded it to get the metadata. As you've noted, the original file names are stored in xl\drawings\vmlDrawing1.vml (once you've extracted the xml files from the excel file by appending .zip to the filename and then running an unzip utility on it). I did find the file name, but not the path or file type, so I'm fairly certain that the path and file type aren't preserved.
If just the file name is sufficient for you, then that file contains information for each drawing that you have, and those will include the cell location, although they're 0 based, so you'd have to add one to get the actual row and column. My question is two part:
1) Is the file name alone sufficient, or did you need the entire path? If you needed the entire path, I think you're out of luck, since the paths are on a different computer and you can't even search for them if you do extract the file name.
2) If that is all you need, does the solution have to be VBA? In the past, I have programmatically unzipped and manipulated the xml base files, but it's a little tricky. It's simplified by the fact that you only have to read out the data, so that's a plus. I did it in .net before, but I'm sure that if it had to be VBA it could be done, but it would be simpler if you were open to the type of solution.
Let me know, I'd be happy to help you out.
====================================================================================
Try this: make a copy of the spreadsheet, append .zip (test.xlsm.zip), and then extract the files manually. Change vmlPath to the location of your xl\drawings\vmlDrawing1.vml file. Then run this. I did make some assumptions, for instance, I assumed that the order of the nodes and attributes would always be the same and so I used hardcoded indexes (shp.attributes(0), etc) instead of using logic to make sure I had the correct node or attribute, but you seem like you know your way around VBA, so I'm just going to code a barebones. This will need a reference to Microsoft XML 6.0.
Sub vmlParse()
Dim vmlPath As String: vmlPath = "C:\Users\Lenovo\Desktop\test - Copy.xlsm\xl\drawings\vmlDrawing1.vml"
Dim this As Worksheet: Set this = ActiveSheet
Dim doc As New DOMDocument, shps As IXMLDOMNodeList
Dim shp As IXMLDOMNode, n As IXMLDOMNode, a As IXMLDOMAttribute
Dim fileName As String, productID As String
Dim rng As Range, r As Long, c As Long
doc.Load vmlPath
Set shps = doc.getElementsByTagName("x:ClientData")
For Each shp In shps
If shp.Attributes(0).nodeValue = "Note" Then
r = 0: c = 0
For Each a In shp.ParentNode.FirstChild.Attributes
If a.nodeName = "o:title" Then
fileName = a.nodeValue
Exit For
End If
Next
For Each n In shp.childNodes
If n.nodeName = "x:Row" Then r = n.text
If n.nodeName = "x:Column" Then c = n.text
Next
Set rng = this.Cells(r + 1, c + 1)
productID = rng.Value
'now you have the productID, the fileName, and the cell location
End If
Next
End Sub
Let me know how that worked out for you.
If c4 contains your comment:
Set shp = Range("C4").Comment.Shape
if shp.Fill.TextureType = msoTextureUserDefined then
end if

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

Resources