EDIT: I took PeterT's advice from comment and reprogrammed this using Dir() instead of FileSystem object. My new code, plus one alteration I made to it, scans my target directory in just about a minute. Still not ideal, but a huge improvement from where I started. If anyone knows how to further reduce the processing time, please, lmk!
The alteration is that I include the year in the Dir(filepath/filename) to search for, which should be the current year. I'm lucky in that the reference files have their dates saved as part of their filenames.
Note: Forgot to mention that the directory/reference files are saved on a network folder, which would lend to explain why accessing the file properties is taking soo long.
Here is the new code:
Public Function FindMostRecent_inYear() As String
'Debug
Dim i As Integer
i = 0
Dim StartTime As Double
Dim MinutesElapsed As String
'Remember time when macro starts
StartTime = Timer
Dim FolderName As String
Dim iFileName As String
Dim searchYear As String
searchYear = ActiveWorkbook.Sheets("CONFIG_MACRO").Range("A2").Value
Dim iDateLastMod As Date
Dim iFoundFile As String
Dim DateMax As Date
DateMax = 0
FolderName = "C:\Network\Folder\Data\"
iFileName = Dir(FolderName & "ALL_REF_FILES_START_W_THIS" & searchYear & "*.xlsx")
Do While iFileName <> ""
i = i + 1
iDateLastMod = FileDateTime(FolderName & iFileName)
If iDateLastMod > DateMax Then
iFoundFile = iFileName
DateMax = iDateLastMod
End If
iFileName = Dir()
Loop
MinutesElapsed = Format((Timer - StartTime) / 86400, "hh:mm:ss")
MsgBox "This code ran successfully in " & MinutesElapsed & " minutes", vbInformation
FindMostRecent_inYear = iFoundFile
End Function
!
My code is trying to scan a directory of excel files (~650 .xlsx files) and find the most recent modified file. It then returns the most recent modified file.
When I went to run it, it made excel non-responsive so I got to debugging, I found that it doesn't seem to be an infinite loop, rather an efficiency issue:
A few lines of code, which effectively is run ~650 times, take each anywhere from 1.4 s to 2.5 seconds each time. So at best its gonna take 30 mins for it to scan the whole directory, or longer.. waaay too long. The lines of code that are taking so long are accessing the properties of each file in the directory, specifically the file.Name, file.Type and the file.datelastmodified, such as:
iName = iFile.Name
iDateLastMod = iFile.datelastmodified
...
if iFile.Type = "Microsoft Excel Worksheet" Then
Is there anyway to check, in each iteration of 650, the file properties quickly?
I should note that I know for a fact all of the files in the directory are .xlsx files, So this I don't technically have to check, but I want to make my code failsafe, if I can. I do have to check the filename and date last modified..
Below is the code without debugging:
Public Function FindMostRecentWorkbook()
' iFile is iteration file
Dim iFile As Object
Dim DateMax As Date
Dim iFoundFile As Object
'RIDD_Folder is Raw Input Data Directory Folder
Dim RIDD_Folder As Object
Dim FileSysObj As Object
Dim strFileName As String
Set FileSysObj = CreateObject("scripting.filesystemobject")
Set RIDD_Folder = FileSysObj.GetFolder("C:\Filepath\Output\data\PROTECTED")
DateMax = 0
Dim iName As String
Dim iDateLastMod As Date
For Each iFile In RIDD_Folder.Files
iName = iFile.Name
iDateLastMod = iFile.datelastmodified
With iFile
If iFile.Type = "Microsoft Excel Worksheet" Then
If iName Like "ALL_REF_FILES_START_W_THIS" And iDateLastMod > DateMax Then
Set iFoundFile = iFile
DateMax = iDateLastMod
End If
End If
End With
Next iFile
Set FindMostRecentWorkbook = iFoundFile
End Function
Here is the code with debugging included:
Public Function FindMostRecentWorkbook()
'Debug code
'iterations
Dim c, x, i, iLike As Integer
c = 0
x = 0
i = 0
iLike = 0
'timer
Dim StartTime_Assign, StartTime_With, StartTime_IfType, StartTime_IfName As Double
Dim SecondsElapsed As Double
' iFile is iteration file
Dim iFile As Object
Dim DateMax As Date
Dim iFoundFile As Object
'RIDD_Folder is Raw Input Data Directory Folder
Dim RIDD_Folder As Object
Dim FileSysObj As Object
Dim strFileName As String
Set FileSysObj = CreateObject("scripting.filesystemobject")
Set RIDD_Folder = FileSysObj.GetFolder("C:\Filepath\Output\data\PROTECTED")
DateMax = 0
Dim iName As String
Dim iDateLastMod As Date
'Dim iFileType As Type
For Each iFile In RIDD_Folder.Files
i = i + 1
StartTime_Assign = Timer
iName = iFile.Name
iDateLastMod = iFile.datelastmodified
SecondsElapsed = Round(Timer - StartTime_Assign, 2)
Debug.Print "Time elapsed in Assign:" & SecondsElapsed
StartTime_With = Timer
With iFile
StartTime_IfType = Timer
If iFile.Type = "Microsoft Excel Worksheet" Then
StartTime_IfName = Timer
If iName Like "ALL_REF_FILES_START_W_THIS" And iDateLastMod > DateMax Then
iLike = iLike + 1
Set iFoundFile = iFile
DateMax = iDateLastMod
End If
SecondsElapsed = Round(Timer - StartTime_IfName, 2)
Debug.Print "Time elapsed in If iName Like ....:" & SecondsElapsed
End If
SecondsElapsed = Round(Timer - StartTime_IfType, 2)
Debug.Print "Time elapsed in If iFile.Type = ...:" & SecondsElapsed
End With
SecondsElapsed = Round(Timer - StartTime_With, 2)
Debug.Print "Time elapsed in With iFile:" & SecondsElapsed
If (((i / 10) <> 0) And ((i Mod 10) = 0)) Then
'breakpoint on below line
x = x + 1
End If
If (((i / 100) <> 0) And ((i Mod 100) = 0)) Then
c = c + 1
End If
Next iFile
Set FindMostRecentWorkbook = iFoundFile
End Function
When tested this debug code printed this:
Time elapsed in Assign:2.49000000953674
Time elapsed in If iName Like ....:0
Time elapsed in If iFile.Type = ...:1.5
Time elapsed in With iFile:0
Time elapsed in Assign:1.73000001907349
Time elapsed in If iName Like ....:0
Time elapsed in If iFile.Type = ...:1.6599999666214
Time elapsed in With iFile:0
Time elapsed in Assign:1.76999998092651
Time elapsed in If iName Like ....:0
Time elapsed in If iFile.Type = ...:1.51999998092651
Time elapsed in With iFile:0
Time elapsed in Assign:1.75
Time elapsed in If iName Like ....:0
Time elapsed in If iFile.Type = ...:1.5
Time elapsed in With iFile:0
...
In doing some testing where I had to read the directory for a large number of files from a network drive, I found that the windows Command Prompt dir command executed much faster than the VBA dir command or the FileSystemObject.
I also found that writing the results to a temporary file resulted in no screen flickering, whereas I had problems with screens when trying to read it directly into VBA.
In the code below, I make use of that. I have used arguments for the dir command so that it returns the desired files sorted in reverse order by date/time last written.
Also, note the use of arguments and wild cards to construct a string which includes the base folder, the starting part of the file name, and the various xls file extensions.
Since dir will return the file list properly sorted, one only needs to return the first entry in the file.
Also note that I used early-binding, but you could convert to late-binding if inconvenient.
At the end, I debug.print the full path of the most recent file.
I can't imagine this would take more than a second to locate the most recent excel file.
'Set References:
' Windows Script Host Object Model
' Microsoft Scripting Runtime
Option Explicit
Sub GetMostRecentFile()
Dim WSH As WshShell, lErrCode As Long
Dim FSO As FileSystemObject, TS As TextStream
Dim sTemp As String
Dim MostRecentFile As String
Const sRIDD_Folder_Path As String = "c:\users\ron\documents\" 'note terminal backslash
Const sFileSpec As String = "Book1*.xls*"
sTemp = Environ("Temp") & "\FileList.txt"
Set WSH = New WshShell
'note /U to enable Unicode output, as some names have char codes > 127 which are altered by redirection
lErrCode = WSH.Run("CMD /U /c dir """ & sRIDD_Folder_Path & sFileSpec & """ /TW /O-d /B > " & sTemp, xlHidden, True)
If Not lErrCode = 0 Then
MsgBox "Problem Reading Directory" & _
vbLf & "Error Code " & lErrCode
Exit Sub
End If
Set FSO = New FileSystemObject
Set TS = FSO.OpenTextFile(sTemp, ForReading, False, TristateTrue)
MostRecentFile = Split(TS.ReadAll, vbLf)(0)
TS.Close
FSO.DeleteFile sTemp
Set FSO = Nothing
Debug.Print sRIDD_Folder_Path & MostRecentFile
End Sub
Related
I've written some VBA code using file objects to go into a folder, search for particular files (CSV) that meet certain criteria (contain "HR" in filename and created within specified date range), and copy/paste information out of that file into a master file. The master file is typically a compilation of 250+ workbooks.
The macro works as it should, but it takes about 12 minutes to run, which is a bit excessive. I believe it takes so long to run because it is indexing a folder with 30,000+ files in it.
I've copied the relevant lines of my code below, if anyone is aware of any modifications I could make that would decrease the duration of my macro, I would really appreciate it. I'm relatively new to VBA and coding in general, so I'm learning as I go with these sorts of things! Thanks!
Dim FilePath As String
Dim FileName As String
Dim objFSO As FileSystemObject
Dim objFolder As Folder
Dim objFile As file
Dim fileDate As Date
Dim firstDate As Date
Dim secondDate As Date
'Defining the user-input variables
Worksheets("Sheet1").Activate
firstDate = Cells(2, "E").Value
secondDate = Cells(3, "E").Value
'FilePath to information, defining file objects
FilePath = "\\SRV-1\process\DUMP\"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder(FilePath)
'Going through Dump folder and finding high resolution files created within the date range
For Each objFile In objFolder.Files
'Checking to see if the file contains the string "HR", indicating high resolution.
If InStr(1, objFile.Name, "HR") Then GoTo Line1 Else GoTo Line3
Line1:
'Storing the file as a variable and checking its creation date
FileName = objFile.Name
OpenFile = FilePath & FileName
fileDate = FileDateTime(OpenFile)
'Checking to see if the file was created between the user input master roll start/end dates
If firstDate < fileDate And secondDate > fileDate Then GoTo Line2 Else GoTo Line3
Line2:
Do stuff: open dump workbook, copy/pase certain range into main workbook, close dump workbook, next objFile
Line3:
Next objFile
This ought to show some improvement, considering the ratio of HR files to total files (250 / 30,000).
Using Dir Function, Minimize reliance on FileSystemObject
The idea here is to use the Dir function first to get a list of all file names that contain the "HR" substring, and only use the FileSystemObject against those files to get the timestamp information -- there's no use incurring the overhead of FSO on every file in that directory.
Then, we process only those files which match the "HR" criteria:
Sub usingDir()
Dim folderPath As String
Dim fileName As String
Dim filesToProcess As New Collection
Dim item As Variant
Dim fileDate As Date
Dim firstDate As Date
Dim secondDate As Date
'Defining the user-input variables
firstDate = Cells(2, "E").Value
secondDate = Cells(3, "E").Value
folderPath = "\\SRV-1\process\DUMP\"
' Gets a collection of files matching the "HR" criteria
fileName = Dir(folderPath)
Do While Not fileName = ""
If InStr(fileName, "HR") > 0 Then
'Only processing files with "HR"
filesToProcess.Add (folderPath & fileName)
End If
fileName = Dir
Loop
'Now we deal only with the "HR" files:
With CreateObject("Scripting.FileSystemObject")
For Each item In filesToProcess
' Check the date last modified
fileDate = .GetFile(item).DateLastModified ' modify as needed
If firstDate < fileDate And secondDate > fileDate Then
'
'
Debug.Print item
'your code to Do Stuff goes here
'
'
'
End If
Next
End With
End Sub
UPDATE: Without Using the FileSystemObject
This was nagging at me, and I figured there must be a way to get the timestamp information without relying on FileSystemObject. There is. We'll still use Dir to traverse the files, but now we'll eliminate any reference to FileSystemObject and replace with some fancy WinAPI function calls. Check out Chip Pearson's article here and download the .bas modules. You'll need the following two files imported to your VBProject:
modGetSetFileTimes
modTimeConversionFunctions
And then you can do something like this:
Option Explicit
Sub withoutFSO()
Dim folderPath As String
Dim FileName As String
Dim filesToProcess As New Collection
Dim item As Variant
Dim fileDate As Date
Dim firstDate As Date
Dim secondDate As Date
'Defining the user-input variables
firstDate = Cells(2, "E").Value
secondDate = Cells(3, "E").Value
folderPath = "\\Your\Path"
' Gets a collection of files matching the "HR" criteria and our Date range
FileName = Dir(folderPath)
Do While Not FileName = ""
'Only processing files with "HR"
If InStr(FileName, "HR") > 0 Then
' Only process files that meet our date criteria
fileDate = CDate(modGetSetFileTimes.GetFileDateTime(CStr(item), FileDateLastModified))
If firstDate < fileDate And secondDate > fileDate Then
filesToProcess.Add (folderPath & FileName)
End If
End If
FileName = Dir
Loop
'Now we deal only with the matching files:
For Each item In filesToProcess
Debug.Print item
Debug.Print fileDate
'your code to Do Stuff goes here
'
'
'
Next
End Sub
This should be an improvement even over my original answer, and, if combined with a more efficient manner of retrieving data (i.e., using ADO instead of Workbooks.Open, if possible) then you should be very optimized.
Take a look at Power Query -- it's a Microsoft add-in for Excel versions 2012 & 2013, and built-in to 2016. Setting up PQ to do this will be amazingly fast, and the 'script' is reusable! No VBA needed.
You can search and combine the multiple files on the specified criteria, but then merge or append to the new/master file, too. For efficiency, rather than processing each file individually, might I suggest gathering up all the data files (by your criteria), combining them to one table, then use the new table to merge/append to the new/master
Hope this helps...
In addition to using the Dir function instead of FileSystemObject, if you cannot automate PowerQuery, and all you need is the data and not the formatting, consider making a direct data connection to the source workbooks using ADODB.
Add a reference to Microsoft ActiveX Data Objects 6.1 Library (via Tools -> References...). There may be versions other than 6.1; choose the highest.
Then you can use something like the following code:
Dim fso As New Scripting.FileSystemObject
Dim filepath As Variant
For Each filepath In filesToProcess
' Check the date last modified
fileDate = fso.GetFile(item).DateLastModified ' modify as needed
If firstDate < fileDate And secondDate > fileDate Then
Dim connectionString As String
connectionString = _
"Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=""" & filepath & """;" & _
"Extended Properties=""Excel 12.0;HDR=No"""
Dim worksheetName As String
worksheetName = "Sheet1"
' There can be multiple worksheets per workbook.
' If you are only interested in one worksheet per workbook, then fill in worksheetName somehow
' Otherwise, you will probably need an inner loop to iterate over all the worksheets
Dim sql As String
sql = _
"SELECT * " & _
"FROM [" & worksheetName & "$]"
Dim rs As New ADODB.Recordset
rs.Open sql, connectionString
destinationWorksheet.Range("A1").CopyFromRecordset rs
rs.Close
Set rs = Nothing
End If
Next
It took a long time because for each interation you pass the information to the main worksheet.
In this case is better use a multidimensional array to keep the information and in the end of the process you pass the the array info in the main worksheet.
I dont know what information you get in each worksheet, soo i cant create an didatical example for you.
I have an issue and I need your help. here is the problem. I have inside a folder some excel files that I have to open automatically in order to make some operations. Those files have the same name except the number of the files like this:
Folder name : Extraction_Files
Files name : - "System_Extraction_Supplier_1"
- "System_Extraction_Supplier_2"
- "System_Extraction_Supplier_3"
The number of files can change so i used a loop Do While to count the number of files, then the plan is to use a loop for I =1 to ( number of files) to open all of theme.
please read my code. I know that i used a wrong way to read file name using a loop for but I share it because I don't have an other idea.
Here is my code :
Sub OpenFiles ()
Dim MainPath as String
Dim CommonPath as String
Dim Count As Integer
Dim i As Integer
' the main path is " C:\Desktop\Extraction_Files\System_Extraction_Supplier_i"
'with i = 1 to Count ( file number )
CommonPath = "C:\Desktop\Extraction_Files\System_Extraction_Supplier_*"
'counting automatically the file number
Filename = Dir ( CommonPath )
Do While Filename <> ""
Count = Count + 1
Filename = Dir ()
Loop
'the issue is below because this code generate a MsgBox showing a MainPath with the index i like this
'"C:\Desktop\Extraction_Files\System_Extraction_Supplier_i"
' so vba can not find the files
For i = 1 To count
MainPath = "C:\Desktop\Extraction_Files\System_Extraction_Supplier_" & "i"
MsgBox MainPath &
Workbooks.Open MainPath
Next
End Sub
what is the best approach to this?
Why not count as you open them. You're already identifying them so why not open each file as you go:
Sub OpenFiles()
Dim Filename As String
Dim CommonPath As String
Dim Count As Integer
CommonPath = "C:\Desktop\Extraction_Files\"
Filename = Dir(CommonPath & "System_Extraction_Supplier_*")
Do While Filename <> ""
MsgBox Filename
Workbooks.Open CommonPath & Filename
Count = Count + 1
Filename = Dir()
Loop
End Sub
PS. It might be worth adding .xl* or similar to the end of your search pattern to prevent Excel trying to open files that aren't Excel files:
Filename = Dir(CommonPath & "System_Extraction_Supplier_*.xl*")
If you want to open all folders, in a specific folder, which start with "NewFile_", one loop only is needed:
Sub OpenFolders()
Dim path As String: path = ""C:\Desktop\Extraction_Files\""
Dim fileStart As String: fileStart = "System_Extraction_Supplier_"
Dim Fso As Object
Dim objFolder As Object
Set Fso = CreateObject("Scripting.FileSystemObject")
Set objFolder = Fso.GetFolder(path)
For Each objSubFolder In objFolder.subfolders
If InStr(1, objSubFolder.Name, fileStart) Then
Shell "explorer.exe " & objSubFolder, vbNormalFocus
Debug.Print objSubFolder.Name
End If
Next objSubFolder
End Sub
Folders in vba are opened with the Shell "explorer.exe " command. The code opens every folder in "C:\yourFile\", which contains NewFile_ in the name. This check is done with If InStr(1, objSubFolder.Name, fileStart) Then.
just starting to learn VBA for excel and experimenting in automating my routine work.
I have a workbook which some of the contents are copied from other files. In the same file directory, i have several files that data i copied with. The problem is the files have several versioning, for example:
companyA_20151101.xlx
companyA_20151105.xlx
companyA_20151106.xlx
companyB_20151105.xlx
companyC_20151109.xlx
I take documents from company A to C, but having problem due to the date. Would it be possible to tell VBA just pick the latest version (i.e. for companyA takes the one with 06 date)?
You could create a UDF to return a string with the correct file name. I've assumed from the naming convention that the most recent file is actually created on that date and therefore will have the most recent Creation Date property.
Function GetRecentFile(partialFileName As String) As String
Dim files As Variant
Dim checkDate As Date
Dim returnFile As String
With CreateObject("System.FileScriptingObject")
files = Filter(Split(CreateObject("WScript.Shell").Exec("CMD /C DIR """ & partialFileName & _
"*.xl*"" /S /B /A:-D").StdOut.ReadAll, vbCrLf), ".")
checkDate = .GetFile(CStr(files(0))).DateCreated
For Each file In files
If .GetFile(CStr(file)).DateCreated > checkDate Then
checkDate = .GetFile(CStr(file)).DateCreated
returnFile = CStr(file)
End If
Next
End With
GetRecentFile = returnFile
End Function
Use like so:
Sub MM()
Dim myFile As String, wb As Excel.Workbook
myFile = GetRecentFile("C:\Users\MM\Work Files\CompanyA")
If Not myFile = vbNullString Then
Set wb = Workbooks.Open(myFile)
End If
End Sub
I've approached this slightly differently and am using the date suffix on the filename to determine which is the 'latest' file:
Public Function MostRecentCompanyFile(ByRef strCompany As String, _
ByRef strDirectory As String) As String
Dim strDir As String
Dim datDateSuffix As Date
Dim strLatest As String
Dim datLatest As Date
strDir = Dir(strDirectory & "\" & strCompany & "*")
Do Until Len(strDir) = 0
datDateSuffix = StripDate(strDir)
If Len(strLatest) = 0 Then
'the first iteration
strLatest = strDir
datLatest = datDateSuffix
ElseIf datDateSuffix > datLatest Then
'this file has a later date suffix so this is now the latest
strLatest = strDir
datLatest = datDateSuffix
End If
'get the next file
strDir = Dir
Loop
MostRecentCompanyFile = strLatest
End Function
Private Function StripDate(ByRef strFileName As String) As Date
Dim intPos As Integer
Dim strDate As String
Dim datDate As Date
'assume the date suffix occurs after the underscore in the file name and is in the format yyyymmdd
intPos = InStr(1, strFileName, "_")
strDate = Mid$(strFileName, intPos + 1, 8)
datDate = DateSerial(Left$(strDate, 4), Mid$(strDate, 5, 2), Right$(strDate, 2))
StripDate = datDate
End Function
Here, we are:
Looping through all the files in the given strDirectory.
Stripping off the date suffix (using the StripDate method).
Comparing this date to all others for the given strCompany.
I would like to write a function to would allow me to use Print #Debug, "text" throughout my future modules to collect debug statements.
Sub output_debug()
Dim WshShell As Object
Dim Desktop As String
Dim Debug As Integer
Debug = FreeFile()
Set WshShell = CreateObject("WScript.shell")
Desktop = WshShell.specialfolders("Desktop")
Open Desktop & "\VBA_output.txt" For Output As #Debug
Print #Debug, "test"
Close #Debug
End Sub
How can I move from the above, to defining a function that would allow me to use call output_debug() in a module so all my Print #Debug, would print to that file ? I would imagine I need to create another function called close_output() that has close #Debug
I did something like this in the past. Here is what I came up with. It relies on having a reference to Microsoft Scripting Runtime in any project that uses it. You can store the following subs in a module e.g. DebugLogger (which is what I use) that can be first exported then imported into any module that you want to have this functionality. It mimics the behavior of Debug.Print but sends the output to a file whose name is a function of the workbook's name. I toyed with the idea of time-stamping individual entries but rejected the idea as being too far from the functionality of Debug.Print (I do, however, time stamp the date of creation). Once you import the module and establish the right reference then you can just use DebugLog anywhere you would have used DebugPrint. As a default it also prints to the debug window. You can drop that part of the code entirely or switch what the default is.
Function GetFullDebugName() As String
'This function returns a string of the form
'*xldebug.txt, where *.* is the full name of the workbook
Dim MyName As String
Dim NameParts As Variant
MyName = ThisWorkbook.FullName
NameParts = Split(MyName, ".")
GetFullDebugName = NameParts(0) & "xldebug.txt"
End Function
Sub CreateDebugFile()
'file created in same directory as
'calling workbook
Dim DebugName As String
Dim fso As FileSystemObject
Dim MyStream As TextStream
Set fso = New FileSystemObject
DebugName = GetFullDebugName
Set MyStream = fso.CreateTextFile(DebugName)
MyStream.WriteLine "This debug file was created " _
& FormatDateTime(Date) _
& " at " & FormatDateTime(Time)
MyStream.Close
End Sub
Sub DebugLog(DebugItem As Variant, Optional ToImmediate As Boolean = True)
Dim DebugName As String
Dim fso As FileSystemObject
Dim MyStream As TextStream
Set fso = New FileSystemObject
DebugName = GetFullDebugName
'check to see if DebugFile exist
'if not, create it:
If Not fso.FileExists(DebugName) Then CreateDebugFile
Set MyStream = fso.OpenTextFile(DebugName, ForAppending)
MyStream.WriteLine DebugItem
MyStream.Close
If ToImmediate Then Debug.Print DebugItem
End Sub
Try a subroutine like this...
It will log text to a text file with a date stamp, so new file new day.
You have an option to pass it the ERR object if you trap the error in your code and it will log the error message with a highlight.
call debuglog("my log entry")
call debuglog("my log entry",err)
Public Sub DebugLog(sLogEntry As String, Optional ByVal oErr As Object)
' write debug information to a log file
Dim iFile As Integer
Dim sDirectory As String
Dim errNumber, errDescription As Variant
Dim l As Integer
If Not oErr Is Nothing Then
errNumber = oErr.Number
errDescription = oErr.Description
l = IIf(Len(errDescription) > Len(sLogEntry), Len(errDescription), Len(sLogEntry))
End If
On Error GoTo bail
sfilename = VBA.Environ("Homedrive") & VBA.Environ("Homepath") & "\My Documents\Debuglog" & "\debuglog" & Format$(Now, "YYMMDD") & ".txt"
iFile = FreeFile
Open sfilename For Append As iFile
If Not oErr Is Nothing Then
sLogEntry = "/" & String(5 + (l - Len(sLogEntry)), "-") & " " & sLogEntry & " " & String(5 + (l - Len(sLogEntry)), "-") & "\"
Print #iFile, Now; " "; sLogEntry
Print #iFile, Now; " "; errNumber
Print #iFile, Now; " "; errDescription
Print #iFile, Now; " "; "\" & String(Len(sLogEntry) - 2, "-") & "/"
Else
Print #iFile, Now; " "; sLogEntry
End If
bail:
Close iFile
End Sub
example logfile output
27/03/2015 10:44:27 -- COMIT Form Initialize - Complete
27/03/2015 10:44:27 - COMIT Active
27/03/2015 10:44:34 /----- -- Error Populating Opportunity Form: frmBluesheet.PopulateForm() -----\
27/03/2015 10:44:34 381
27/03/2015 10:44:34 Could not get the Column property. Invalid property array index.
27/03/2015 10:44:34 \-----------------------------------------------------------------------------/
I'm trying to save excel file into a specific path.
So basically, when I click the button, I'm creating a folder, and want to save the file inside that folder.
The created folder has the current month as name. I'm trying to save into that current month folder.
'Create folder as Month Name. Save filename as date inside "month".
Dim sDate As String = DateTime.Now.ToString("yyyy-MM-dd") & "_" & DateTime.Now.ToString("HH-mm-ss")
Dim sMonth As String = DateTime.Now.ToString("MMMM")
Dim sFolder = Application.StartupPath & "\Resources\Excel\"
My.Computer.FileSystem.CreateDirectory(sFolder & Format(sMonth))
Dim sfinal = Path.Combine(sFolder, sMonth)
xlSh.SaveAs(sfinal & Format(sDate) & ".xlsx")
xlApp.Workbooks.Close()
xlApp.Quit()
As it is, this code doesn't give me any errors. But instead of creating a folder named "March" <-current month and saving inside it, it saves the file in \Excel\ and it also creates folder in the same place.
you could use the following function (similar to .NET System.IO.Path.Combine)
Function PathCombine(path1 As String, path2 As String)
Dim combined As String
combined = path1
If Right$(path1, 1) <> Application.PathSeparator Then
combined = combined & Application.PathSeparator
End If
combined = combined & path2
PathCombine = combined
End Function
Hope this helps!
After long hours of excruciating pain, I've finally did it!
Apparently I was missing an "\"
Since "sMonth" became dynamic name, which later I wanted to use as path, and save files in that folder. I needed to simply put that "\" after sMonth, to tell it to save inside it.
Before I realize this... I've broken down, simplified the code as much as I could so I can logically connect the pieces. What I ended up with, is something slightly different. Now the SaveAS properly saves the file inside the new folder.
Dim sDate As String
sDate = DateTime.Now.ToString("yyyy-MM-dd") & "_" & DateTime.Now.ToString("HH-mm-ss")
Dim sMonth As String
sMonth = DateTime.Now.ToString("MMMM")
Dim sFileName As String
sFileName = sDate + ".xlsx"
Dim sFolder As String
sFolder = Application.StartupPath & "\Resources\Excel\"
Dim sfinal As String
sfinal = (sFolder & sMonth & "\") '<- this thingie here o.O
My.Computer.FileSystem.CreateDirectory(sFolder & Format(sMonth))
xlSh.SaveAs(sfinal & Format(sFileName))
xlApp.Workbooks.Close()
xlApp.Quit()
Thanks for the help.
You don't appear to actually be setting the save path to the created directory. Instead, I believe you're appending the month to the beginning of the file name in the xlSh.SaveAs(sFinal & Format(sDate) & ".xlsx"). Basically (though I'm not sure of the specific command) you need to navigate to the folder you created after you create it. Probably something to the format of
My.Computer.FileSystem.ChangeDirectory(sFolder & Format(sMonth))
though I don't know that that specific command actually exists as I wrote it.
To those who have been wondering wtf I was doing with all this, here is the full sub. And if anyone needs something similar. Thanks for the support. Problem has been resolved.
Private Sub Button_Click(sender As Object, e As EventArgs) Handles Button.Click
Dim xlApp As Excel.Application
Dim xlSh As Excel.Worksheet
xlApp = New Excel.Application
xlApp.Workbooks.Add()
xlSh = xlApp.Workbooks(1).Worksheets(1)
'Items from listbox1 to be exported into excel, second row, second column.
Dim row As Integer = 2
Dim col As Integer = 2
For i As Integer = 0 To ListBox1.Items.Count - 1
xlSh.Cells(row, col) = ListBox1.Items(i)
row = row + 1
Next
row += 1
col = 1
'Items from listbox2 to be exported into excel, second row, third column.
Dim row2 As Integer = 2
Dim col2 As Integer = 3
For i As Integer = 0 To ListBox2.Items.Count - 1
xlSh.Cells(row2, col2) = ListBox2.Items(i)
row2 = row2 + 1
Next
row2 += 1
col2 = 1
'Create folder as Month Name. Save filename as date inside that folder.
'Make filename be yyyy-MM-DD_HH-mm-ss
Dim sDate As String
sDate = DateTime.Now.ToString("yyyy-MM-dd") & "_" & DateTime.Now.ToString("HH-mm-ss")
'This will be used as name for the new folder.
Dim sMonth As String
sMonth = DateTime.Now.ToString("MMMM")
'Filename + extension.
Dim sFileName As String
sFileName = sDate + ".xlsx"
'This is the path.
Dim sFolder As String
sFolder = Application.StartupPath & "\Resources\Excel\"
'This is the path combined with sMonth to make the final path.
Dim sfinal As String
sfinal = (sFolder & sMonth & "\")
'Check if folder with the name sMonth already exists.
If Dir(sFolder, vbDirectory) = sMonth Then
'If it exist, then simply save the file inside the folder.
xlSh.SaveAs(sfinal & Format(sFileName))
Else
'If it doesn't exist:
'This is the creation of sMonth folder, inside "\excel\.
My.Computer.FileSystem.CreateDirectory(sFolder & Format(sMonth))
'This saves the excel file at path sfinal, with filename of sFileName
xlSh.SaveAs(sfinal & Format(sFileName))
End If
'Close everything.
xlApp.Workbooks.Close()
xlApp.Quit()
End Sub
I find this method to be much easier.
Create a FileSystemObject and use BuildPath Method, like so:
Set fs = CreateObject("Scripting.FileSystemObject")
skPath = fs.BuildPath(ActiveDocument.Path, "Survival Story of Sword King")
Attention: ActiveDocument.Path is current directory in Word and does not work in excel or other. for excel it would be ActiveWorkbook.Path
My point is some methods or namespace are application specific.