I am working on automating the saving procedure of our purchase orders that we do through an Excel workbook. Instead of the user having to copy the template into the correct directory and renaming it with the correct order number that’s next in the sequence along with the date (for e.g. the previous order was order number SJ-K1880 placed on the 7th July 2016 with filename KO_SJ-K1880_070716, so the next order number would be SJ-K1881 placed on the 11th of July 2016 with filename KO_SJ-K1881_110716), the user only needs to click a Save button and it will save the workbook in the correct directory under the right filename automatically following the sequence. Here’s an example of the full directory of one such file:
C:\Users\User\Desktop\Kyocera Order Doc\
Kyocera Orders\Orders 2016\07 July 2016\
KO SJ-K1880 070716\KO_SJ-K1880_070716.xlsm
Using the current date I have managed to check the existence of the directory up until 07 July 2016 and create it if it doesn’t exist. My problem comes in finding the last folder from that directory (which is KO SJ-K1880 070716 in this example) and using it to determine what the next order number is going to be.
This seems to give you what you want but it relies on an ascending sort of the folder names.
Option Explicit
Sub main()
Dim fldr As String
fldr = Environ("USERPROFILE") & _
"\Desktop\Kyocera Order Doc\Kyocera Orders\Orders 2016\07 July 2016"
Debug.Print mostRecentFolderNdx(fldr)
End Sub
Function mostRecentFolderNdx(base As String)
Dim f As String, lstndx As String
f = Dir(base & "\*", vbDirectory)
Do While CBool(Len(f))
If Not CBool(InStr(1, f, Chr(46))) Then
lstndx = Split(f, Chr(32))(UBound(Split(f, Chr(32))))
End If
f = Dir
Loop
mostRecentFolderNdx = lstndx
End Function
If you are going to rely on an ascending sort order, it is better to have your folders use a naming convention like \20160707\ rather than \07 July 2016\.
Related
Purpose of my question and of the VBA code:
Get specific data (a couple columns) from each one of the "table.csv" file in a network directory. Each networkdirectory/subfolders01/subfolders02 contains one "table.csv" file but 100 other subfolders are included in each network/subfolders01. The other folders are not needed, the only one we are interested in is subfolder02 for each subfolder01. The number of subfolders01 in the network directory is about 15000. However I only need subfolders01 from Jan2020 to Apr2020,for example (200 subfolders).
Final purpose is to trend data.
Issue:
I am trying to understand how I could improve the VBA code that I am currently using.
This code goes through each subfolder one by one and then check the date and file name.
I am wondering if there is a way to add any search filters criteria for subfolder date and name to have a faster loop.
How can we avoid the code to go through each subfolders?
Please see below the code I am using,
I really appreciate your time and hope my request is clear.
'''
Function GetFiles(startPath As String) As Collection
Dim fso As Object, rv As New Collection, colFolders As New Collection, fpath As String
Dim subFolder As Object, f, dMinfold, dtMod
Set fso = CreateObject("Scripting.FileSystemObject")
dMinfold = ThisWorkbook.Sheets("Enter_Date").Cells(2, 1)
colFolders.Add startPath
Do While colFolders.Count > 0
fpath = colFolders(1)
colFolders.Remove 1
'process subfolders
For Each subFolder In fso.getfolder(fpath).subfolders
If subFolder.DateLastModified >= dMinfold Then
colFolders.Add subFolder.Path
End If
Next subFolder
'process files
f = Dir(fso.buildpath(fpath, "*Table.csv"), vbNormal)
Do While f <> ""
f = fso.buildpath(fpath, f)
dtMod = FileDateTime(f)
If dtMod >= dMinfold And Right(f, 3) = "csv" Then
rv.Add f
End If
f = Dir()
Loop
Loop
Set GetFiles = rv
End Function'''
Then I have my code to get transfer data from each file.
Thank you.
I'll put in screenshots to clear up the Get & Transform method, since it is the GUI approach rather than code.
It is possible to filter before loading contents, which will speed things up significantly.
I tried with a few thousand subfolders filtered down to 20, loads instantly.
Here's the initial screen for get data from folder
You can then filter on path. In your case it will be based on the date from the folder name.
Now that it's filtered you can expand the content using the header button.
Inside content, you'll have to expand again to convert from csv to excel table
Choose/rename columns as needed, then hit "close and load" to drop it into excel.
Default is to a new table, but you can "load to" if something more custom is needed.
Here's your output. You can right-click refresh or refresh from vba as needed.
Edit- Just noticed that I used .txt rather than .csv for the files. Might change how a step or two looks in the middle, but the general idea is the same.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I receive a weekly Excel file from my IT department with an updated list of employees, their supervisor, department, etc. Every week, I just drag the file from the email into a designated folder on my computer.
Occasionally, I'll want a VBA script to reference and copy info from the latest version of whatever listing IT has sent to me most recently. The naming convention for the file is always the same: "EmployeeListing_20171211," but obviously with the date in the name being whatever day the file is generated. So next week, I can expect the new file to be named "EmployeeListing_20171218."
Because these files are stored in a shared folder, I have no way of knowing if other people are opening & modifying them, so I don't want the script to go by most recent Date Modified, but instead be able to read the date from the name of the file and select the file that's the newest. And all the questions I've seen related to this seem to point towards opening the file that has the most recent Date Modified, not in whose name includes the most recent date.
To do this, it seems to me like I need to read in the names of all the files in the folder, tell VBA how to convert the string to a date, find the date that's the most recent, and then find the corresponding Excel file that matches this date. But I have no idea where to start. Can anyone help with this?
Here's some code with comments that will get you started.
Sub test()
Dim sFile As String
Dim sPath As String
Dim dtFile As Date
Dim dtMax As Date, sMax As String
Dim sDate As String
'Folder where your files live
sPath = Environ("userprofile") & "\Documents\MyFolder\"
'Get the first file that starts with EmployeeListing_
sFile = Dir(sPath & "EmployeeListing_*")
'If there are no files, the lenght = 0
Do While Len(sFile) > 0
sDate = Split(sFile, "_")(1) 'get the date part of the file name
'turn it into an actual date
dtFile = DateSerial(Left$(sDate, 4), Mid$(sDate, 5, 2), Mid(sDate, 7, 2))
'if it's bigger than any others, store the date and name
If dtFile > dtMax Then
dtMax = dtFile
sMax = sFile
End If
'no arguments means get the next file using the same arguments as
'previosly supplied
sFile = Dir
Loop
'Print the file with the biggest date
Debug.Print sPath & sMax
End Sub
I'm trying to pull back a list of directories that sit inside a dated folder structure. Within each dated folder could be a number of 'Jobs' however i only want to return the name of the 1st level of folders
The below code gets to the right level of folder detail however the result displays the full path
For Each Dir As String In System.IO.Directory.GetDirectories("c:\Working")
Dim dirInfo As New System.IO.DirectoryInfo(Dir)
For Each sDir As String In System.IO.Directory.GetDirectories(dirInfo.ToString)
Dim sdirInfo As New System.IO.DirectoryInfo(sDir)
chkImpExp.Items.Add(sDir)
Next
Next
This would display the following
However i would just like to display the directory name to the right of the 3rd backslash (Westdale - 28023 - Cash+Spirit for example)
Hopefully this is enough information.
Many thanks
' renamed Dir to d as Dir() is already a function in Microsoft.VisualBasic
For Each d In System.IO.Directory.GetDirectories("c:\Working")
For Each sDir In System.IO.Directory.GetDirectories(d)
Dim di = New DirectoryInfo(sDir)
chkImpExp.Items.Add(di.Name())
Next
Next
Try:
chkImpExp.Items.Add(sdirInfo.Name)
At the company I work at, I have a software that I am developing in vb.net. This software uses a web browser control to load an excel file that the employee can modify. If then saves a copy of the excel file as an excel file for future modification, it saves it as a pdf file, to send to the customer, then prints the first page twice. I am trying to create a quote list. Quote File names are structured as follows...
12345 My Company Name Here 10-25-2013.pdf
Is there any way to "extract" just the "My Company Name Here" in the above example. I tried removing all numbers, and then the - and .pdf from the string, but it actually makes it where fewer results appear in the list view control. Any Ideas?
Dim di As New IO.DirectoryInfo("Z:\Quotes\" & Today.Year & "\" & Today.Month _
& " " & MonthName(Today.Month))
Dim diar1 As IO.FileInfo() = di.GetFiles("*.pdf")
Dim dra As IO.FileInfo
ListView1.View = View.Details
ListView1.Columns.Clear()
ListView1.Columns.Add("Quote Number")
ListView1.Columns.Add("Customer Name")
ListView1.Columns(0).Width = -2
ListView1.Columns(1).Width = -2
For Each dra In diar1
If dra.ToString.Contains("Product") = False Or dra.ToString.Contains("Thumbs.db") Then
Dim newIrm() = dra.ToString.Split(" ")
Dim NumericCharacters As New System.Text.RegularExpressions.Regex("\d")
Dim nonNumericOnlyString As String = NumericCharacters.Replace(newIrm(2), String.Empty)
ListView1.Items.Add(New ListViewItem({newIrm(0), newIrm(1) & newIrm(2)}))
End If
Next
Filename Format:
Z:\Quotes\2013\10 October\12345-RR My Company Name Here 10-25-2013.pdf
By assuming that the company name is always surrounded by blank spaces and that all the surrounding text does not contain any, you can use IndexOf and LastIndexOf. Sample code:
Dim input As String = "Z:\Quotes\2013\10 October\12345-RR My Company Name Here 10-25-2013.pdf"
Dim companyName As String = System.IO.Path.GetFileNameWithoutExtension(input)
companyName = companyName.Substring(companyName.IndexOf(" "), companyName.LastIndexOf(" ") - companyName.IndexOf(" ")).Trim()
If these conditions do not fully apply, you would have to describe clearly the constraints in order to update this code. Without systematically-applied constraints, there wouldn't be any way to deliver an accurate solution for this problem.
The postfix (date.pdf) is a constant size assuming your date format uses leading zeros.
The prefix is a variable size, however the first space of the complete file name always comes before the first character of the company name.
Using these two facts, you can easily find the index of the first and last character of the company "extract" the company name using this information.
Alternatively, you can split the file name into an array using space as your delimiter. You can then grab every index of the array, excluding the first and last index, and combine these elements seperated by a space.
Inside Word (2003 or 2007), is there a way to have one Header/Footer that is used by Multiple documents?
I want to be able to change the header/footer in one spot and have it affect multiple documents.
i.e. I have 50 documents and they all have the same header/footer. Instead of opening all 50 documents to make the change, is there a way to link (OLE?) the 50 documents to a main document and only have to change the main document?
If there is not a built in way, has anyone done this using VBA?
I'm not sure how will this will work in practice, but you can insert other files into a Word document as a link.
First create the document with the header/footer content, with the content in the body of the document. Save it.
Then go to one of your 50 documents, go into the header/footer. Go to INSERT | FILE. Locate the first file, then click the little drop-down arrow next to the OPEN button in the Insert File dialog. From the drop-down, select INSERT AS LINK. The content should now show up in the document. If you click in the content, normally it will have a grey background, to indicate it's really a Word field.
Now when you change the first document, you can open the second document, update the field (click anywhere in it and hit F9) and the new content will be pulled in. You can also update fields programmatically pretty easy, or under TOOLS | OPTIONS | PRINT, there's a box to auto update the fields every time the document is printed.
AFAIK to alter a documents header (simply) must be done by having the document open. That said you have a few options. First if the documents are saved in the office XML format then you could open the files using the MSXML library and alter the data in the header. (Or any of the dozens of other ways to alter what is essentially a text file.) If the file(s) are still in the binary format you really only have one of two options. The first is to open the file via vba and alter the header via the document object model. The second would be to figure out the binary format (which is documented) and alter it using the VB6/VBA native binary IO (very non-trivial).
Unless I thought I could gain more time then I was going to lose writing code to alter the documents directly I would probably just loop through all the file in the folder, open them and alter them. As for storing the header somewhere... You could just put the header data in a text file and pull it in. Or keep a document template somewhere.
Here is a very trivial example:
Public Sub Example()
Dim asFiles() As String
Dim lFile As Long
Dim docCrnt As Word.Document
asFiles = GetFiles("C:\Test\", "*.doc")
For lFile = 0& To UBound(asFiles)
Set docCrnt = Word.Documents.Open(asFiles(lFile))
docCrnt.Windows(1).View.SeekView = wdSeekCurrentPageHeader
Selection.Text = "I am the header."
docCrnt.Close True
Next
End Sub
Public Function GetFiles( _
ByVal folderPath As String, _
Optional ByVal pattern As String = vbNullString _
) As String()
Dim sFile As String
Dim sFolder As String
Dim asRtnVal() As String
Dim lIndx As Long
If Right$(folderPath, 1&) = "\" Then
sFolder = folderPath
Else
sFolder = folderPath & "\"
End If
sFile = Dir(sFolder & pattern)
Do While LenB(sFile)
ReDim Preserve asRtnVal(lIndx) As String
asRtnVal(lIndx) = sFolder & sFile
lIndx = lIndx + 1&
sFile = Dir
Loop
If lIndx = 0& Then
ReDim asRtnVal(-1& To -1&) As String
End If
GetFiles = asRtnVal
Erase asRtnVal
End Function