I'm trying to get the one Before the Last modified File in a Folder Using Excel VBA, I have managed to Get the Last Modified File, But I couldn't get the second one.
Herein Below the code I used to get the Last Modified File, without using system Functions or built-in function.
Sub LastFileModified()
Dim fso As New Scripting.FileSystemObject
Dim fill As Scripting.File
Dim i As Integer
Dim ForStep As Integer
Dim Arr() As Variant
ReDim Arr(fso.GetFolder("C:\Users\Shahim\Desktop\xxxx").Files.Count - 1, 1) As Variant
i = 0
For Each fill In fso.GetFolder("C:\Users\Shahim\Desktop\xxxx").Files
Arr(i, 0) = fill.Name
Arr(i, 1) = CDbl(fill.DateLastModified)
i = i + 1
Next fill
Dim filename As String
Dim Initializer As Double
Initializer = Arr(0, 1)
For ForStep = LBound(Arr) To UBound(Arr)
If Arr(ForStep, 1) > Initializer Then
Initializer = Arr(ForStep, 1)
filename = Arr(ForStep, 0)
End If
Next ForStep
Debug.Print filename
Erase Arr
End Sub
Sub SecodLastModified()
Const FLDR_PATH As String = "C:\Test"
Dim i As Long, j As Long, fileArr() As String, maxFiles As Long
Dim fso As Variant, fldr As Variant, f As Variant, l1 As String, l2 As String
Set fso = CreateObject("Scripting.FileSystemObject")
Set fldr = fso.GetFolder(FLDR_PATH)
maxFiles = fldr.Files.Count
ReDim fileArr(1 To maxFiles, 1 To 2)
i = 1
For Each f In fldr.Files
fileArr(i, 1) = f.Name
fileArr(i, 2) = f.DateLastModified
i = i + 1
Next
For i = 1 To maxFiles
For j = i + 1 To maxFiles
If fileArr(j, 2) > fileArr(i, 2) Then
l1 = fileArr(i, 2)
l2 = fileArr(i, 1)
fileArr(i, 2) = fileArr(j, 2)
fileArr(i, 1) = fileArr(j, 1)
fileArr(j, 2) = l1
fileArr(j, 1) = l2
End If
Next
Next
MsgBox fileArr(2, 1)
End Sub
The original answer did not work for me for two reasons.
fileArr(i,2) was not declared a date, and occassionally Excel could not decipher what was the greater date. When I tried to dim this as a date, it said I could not dim an Array.
If temporary files were included, it did not skip over those files.
Here is what worked for me.
Function SecodLastModified(Directory)
Dim FileSys As FileSystemObject
Dim objFile As File, objFile1 As File
Dim myFolder
Dim strFilename As String, strFolder As String, myDir As String
Dim strFilenameFirst As String, strFilenameSecond As String, strFilenameSecond1 As String
Dim dteFile As Date, dteFileSecond1 As Date, dteFileFirst As Date, dteFileSecond As Date
Dim openLastFile
'set up filesys objects
Set FileSys = New FileSystemObject
Set myFolder = FileSys.GetFolder(Directory)
dteFileSecond1 = DateSerial(1900, 1, 1)
dteFile = DateSerial(1900, 1, 1)
'loop through each file and get date last modified. If largest date then store Filename
For Each objFile In myFolder.Files
For Each objFile1 In myFolder.Files
' To prevent opening temporary files
If objFile1.Name Like "*.xlsx" And Left(objFile1.Name, 2) <> "~$" Then
If objFile1.DateLastModified > objFile.DateLastModified Then
dteFileSecond = objFile.DateLastModified
strFilenameSecond = objFile.Name
dteFileFirst = objFile1.DateLastModified
strFilenameFirst = objFile1.Name
' If second file date is greater than current second file, store away as the second file
If dteFileSecond > dteFileSecond1 Then
dteFileSecond1 = objFile.DateLastModified
strFilenameSecond1 = objFile.Name
End If
End If
End If
Next
Next objFile
Set SecodLastModified = Workbooks.Open(Directory & "\" & strFilenameSecond1)
Set FileSys = Nothing
Set myFolder = Nothing
End Function
Related
I need to get some information about some files so im trying to build a function that returns 3 information like this:
sub main()
File = getFile(path) 'future code to list all file information on range
end sub
Function getFile(ByVal path as String)
Dim result() as String
Dim Arquivo as File
Set Folder = FSO.getFolder(Path)
For Each File in Folder.Files
result(n) = File.Name
result2(n) = File.DateLastModified
result3(n) = File.ParentFolder
Next
getFile = Result(), Result2(),Result3()???
End function
Is it possible to return the 3 file information in a single funcion?
Get File Info
Option Explicit
Sub GetFileInfoTEST()
Const FolderPath As String = "C:\Test"
Const wsName As String = "Sheet1"
Const FirstCellAddress As String = "A2"
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim ws As Worksheet: Set ws = wb.Worksheets(wsName)
Dim FileInfo As Variant: FileInfo = GetFileInfo(FolderPath)
Dim rCount As Long: rCount = UBound(FileInfo, 1)
If IsEmpty(FileInfo) Then Exit Sub
With ws.Range(FirstCellAddress).Resize(, UBound(FileInfo, 2))
.Resize(rCount).Value = FileInfo
.Resize(ws.Rows.Count - .Row - rCount + 1).Offset(rCount).ClearContents
.EntireColumn.AutoFit
End With
End Sub
Function GetFileInfo( _
ByVal FolderPath As String) _
As Variant
Dim fso As Object: Set fso = CreateObject("Scripting.FileSystemObject")
If Not fso.FolderExists(FolderPath) Then Exit Function
Dim fsoFolder As Object: Set fsoFolder = fso.GetFolder(FolderPath)
Dim fCount As Long: fCount = fsoFolder.Files.Count
If fCount = 0 Then Exit Function
Dim Data As Variant: ReDim Data(1 To fCount, 1 To 3)
Dim fsoFile As Object
Dim r As Long
For Each fsoFile In fsoFolder.Files
r = r + 1
Data(r, 1) = fsoFile.Name
Data(r, 2) = fsoFile.DateLastModified
Data(r, 3) = fsoFile.ParentFolder
Next fsoFile
GetFileInfo = Data
End Function
Please, try the next adapted function:
Function getFile(ByVal path As String) As Variant
Dim fso As Object, folder As Object, file As Object
Dim arrName, arrDat, arrPar, n As Long
Set fso = CreateObject("Scripting.FileSystemObject")
Set folder = fso.GetFolder(path)
ReDim arrName(folder.files.count - 1)
ReDim arrDat(folder.files.count - 1)
ReDim arrPar(folder.files.count - 1)
For Each file In folder.files
arrName(n) = file.name
arrDat(n) = file.DateLastModified
arrPar(n) = file.parentfolder
n = n + 1
Next
getFile = Array(arrName, arrDat, arrPar)
End Function
It can be tested in the next way:
Sub main()
Dim file As Variant, path As String
path = "the folder path" 'please use here a real path...
file = getFile(path) 'future code to list all file information on range
Debug.Print file(0)(0), file(1)(0), file(2)(0)
End Sub
I have filenames in an folder that start with these:
W1
W2
W3
W10
W22
W34
When I put them into an array, and output them, it comes out like this:
W1
W10
W2
W22
W3
W34
I want to sort it by the number and not like above output. I've tried bubble sort, but doesn't seem to work for me. Any help would be appreciated.
Sub LoopAllExcelFilesInFolder()
'PURPOSE: To loop through all Excel files in a user specified folder and perform a set task on them
'SOURCE: www.TheSpreadsheetGuru.com
Dim myPath As String
Dim myFile As Variant
Dim FldrPicker As FileDialog
'Retrieve Target Folder Path From User
Set FldrPicker = Application.FileDialog(msoFileDialogFolderPicker)
With FldrPicker
.Title = "Select A Target Folder"
.AllowMultiSelect = False
If .Show <> -1 Then GoTo NextCode
myPath = .SelectedItems(1) & "\"
End With
'In Case of Cancel
NextCode:
myPath = myPath
If myPath = "" Then GoTo ResetSettings
'Target Path with Ending Extention
myFile = listfiles(myPath)
'<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<Need help here to sort the array.
End Sub
Here is my get files to array. Unless someone knows a better way to do it. Please help.
Function listfiles(ByVal sPath As String)
Dim vaArray As Variant
Dim i As Integer
Dim oFile As Object
Dim oFSO As Object
Dim oFolder As Object
Dim oFiles As Object
Set oFSO = CreateObject("Scripting.FileSystemObject")
Set oFolder = oFSO.GetFolder(sPath)
Set oFiles = oFolder.Files
If oFiles.Count = 0 Then Exit Function
ReDim vaArray(1 To oFiles.Count)
i = 1
For Each oFile In oFiles
vaArray(i) = oFile.Name
i = i + 1
Next
listfiles = vaArray
End Function
You can modify your sort method to treat the name as [initial character]+[numeric part] and perform the value comparisons accordingly.
Sub tester()
Dim arr, newArr
arr = Array("W33 Horse", "W1 blah", "W2 another", _
"W30 word", "W20 here", "W100 also")
Debug.Print "Original:" & vbLf & Join(arr, vbLf)
SortSpecial arr, "PartOfName"
Debug.Print "Sorted:" & vbLf & Join(arr, vbLf)
End Sub
'Sorts an array using some specific formatting/translation defined in `func`
' func is any function which takes one argument and returns a value to use
' in the sort comparison
Sub SortSpecial(list, func As String)
Dim First As Long, Last As Long, i As Long, j As Long, tmp, arrComp()
First = LBound(list)
Last = UBound(list)
'fill the "compare array...
ReDim arrComp(First To Last)
For i = First To Last
arrComp(i) = Application.Run(func, list(i))
Next i
'now sort by comparing on `arrComp` not `list`
For i = First To Last - 1
For j = i + 1 To Last
If arrComp(i) > arrComp(j) Then
tmp = arrComp(j) 'swap positions in the "comparison" array
arrComp(j) = arrComp(i)
arrComp(i) = tmp
tmp = list(j) '...and in the original array
list(j) = list(i)
list(i) = tmp
End If
Next j
Next i
End Sub
'Reformat by taking the part before the first space, then from that
' the first character, then appending zero-padded numeric remainder
' Eg. "W3" >> "W00000003", "W11" >> "W00000011"
Function PartOfName(ByVal v)
Dim firstPart
firstPart = Split(v, " ")(0) 'before first space
PartOfName = Left(firstPart, 1) & _
Format(Right(firstPart, Len(firstPart) - 1), "00000000")
End Function
You may need to modify the PartOfName function depending on exactly what your filenames look like.
You could create a dictionary from the filenames with the keys being the numeric part of the first part of the filename and the values being the filenames.
That dictionary can then be sorted by key and the sorted filenames returned.
Function listfiles(ByVal sPath As String)
Dim dicFiles As Object
Dim i As Integer
Dim oFile As Variant
Dim oFSO As Object
Dim oFolder As Object
Dim oFiles As Object
Dim ky As Variant
Set oFSO = CreateObject("Scripting.FileSystemObject")
Set oFolder = oFSO.GetFolder(sPath)
Set oFiles = oFolder.files
If oFiles.Count = 0 Then Exit Function
Set dicFiles = CreateObject("Scripting.Dictionary")
For Each oFile In oFiles
ky = Val(Mid(Split(oFile.Name, " ")(0), 2))
dicFiles.Add ky, oFile.Name
Next
Set dicFiles = SortDictionaryByKey(dicFiles)
listfiles = dicFiles.items
End Function
Public Function SortDictionaryByKey(dict As Object) As Object
Dim arrKeys As Object
Dim dictSorted As Object
Dim key As Variant
Set arrKeys = CreateObject("System.Collections.ArrayList")
For Each key In dict
arrKeys.Add key
Next key
arrKeys.Sort
Set dictSorted = CreateObject("Scripting.Dictionary")
For Each key In arrKeys
dictSorted.Add key, dict(key)
Next key
Set SortDictionaryByKey = dictSorted
End Function
I have some .html files which I want to read with vba. I wrote this codes to do what I want but I get
object variable or with block variable not set
error.
Dim arrListATA() As String
Dim arrListTaskNo() As String
Dim arrListDesc() As String
Dim arrIssueNo() As String
Dim arrIssueDate() As String
Dim arrPartNo() As String
Dim arrDMC() As String
Dim arrApplicability() As String
Dim arrDMCModelCode() As String
Dim DMCs As String
Dim arrSubTask() As String
Dim subTasks As String
Dim subs() As Variant
Dim subs1 As String
k = 0
Dim objFile As Scripting.File
Dim objFolder As Scripting.Folder
Set objFSO = CreateObject("Scripting.FileSystemObject")
w = 0
m = 0
b = 0
Set fd = Application.FileDialog(msoFileDialogFolderPicker)
With fd
fd.Filters.Clear
If fd.Show = -1 Then
myTopFolderPath = fd.SelectedItems(1)
Set objFolder = objFSO.GetFolder(myTopFolderPath)
Dim arrSplitedDMC As Variant
Dim arrSubTasks As Variant
For Each objFile In objFolder.Files
Debug.Print myTopFolderPath & "\" & objFile.Name
If Right(objFile.Name, 4) = "html" And Len(objFile.Name) = 33 And Left(objFile.Name, 8) <> "V2500-00" Then
Debug.Print myTopFolderPath & "\" & objFile.Name
Workbooks.Open Filename:=myTopFolderPath & "\" & objFile.Name
Debug.Print "Opened"
lastrow = Cells(Rows.Count, 1).End(xlUp).Row
taskCheckFlag = False
myTemp = ""
partNoFlag = False
mySubTask = ""
For i = 1 To lastrow
txt = Cells(i, 1)
Next i
My folder path and my object names like this
C:\Users\ftk1187\Desktop\V2500 - Copy\V2500-00-70-72-02-00A-363A-D.html
It's not opening my .html files. How can I solve this problem?
The code below actually runs.
Option Explicit
Private Sub Test()
Dim arrListATA() As String
Dim arrListTaskNo() As String
Dim arrListDesc() As String
Dim arrIssueNo() As String
Dim arrIssueDate() As String
Dim arrPartNo() As String
Dim arrDMC() As String
Dim arrApplicability() As String
Dim arrDMCModelCode() As String
Dim DMCs As String
Dim arrSubTask() As String
Dim subTasks As String
Dim subs() As Variant
Dim subs1 As String
Dim objFSO As FileSystemObject
Dim Fd As FileDialog
Dim objFile As Scripting.File
Dim objFolder As Scripting.Folder
Dim arrSplitedDMC As Variant
Dim arrSubTasks As Variant
Dim myTopFolderPath As String
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set Fd = Application.FileDialog(msoFileDialogFolderPicker)
' k = 0
' w = 0
' m = 0
' b = 0
With Fd
.Filters.Clear
If .Show = -1 Then
myTopFolderPath = .SelectedItems(1)
Set objFolder = objFSO.GetFolder(myTopFolderPath)
For Each objFile In objFolder.Files
Debug.Print myTopFolderPath & "\" & objFile.Name
Debug.Print myTopFolderPath
Debug.Print objFile.Name
Debug.Print Right(objFile.Name, 4), Len(objFile.Name), Left(objFile.Name, 8)
' If Right(objFile.Name, 4) = "html" And Len(objFile.Name) = 33 And Left(objFile.Name, 8) <> "V2500-00" Then
' Debug.Print myTopFolderPath & "\" & objFile.Name
' Workbooks.Open Filename:=myTopFolderPath & "\" & objFile.Name
' Debug.Print "Opened"
'
' lastrow = Cells(Rows.Count, 1).End(xlUp).Row
' taskCheckFlag = False
' myTemp = ""
' partNoFlag = False
' mySubTask = ""
'
' For i = 1 To lastrow
' txt = Cells(i, 1)
' Next i
Next objFile
End If
End With
End Sub
You will see that I added Option Explicit at the top and a few declarations that were missing. The variables k, w, m and b are also not declared but if they are numbers their value should already be 0 at that point of the code. According to my research, Excel should be able to open an HTML file but I wonder what it might show.
As a general piece of advice, I would recommend that you construct your code as one Main subroutine which calls other subs and functions, each of them no larger than 10 to 25 lines of code. In your code you already exceed that number in your declarations. The effect is a construct that you can't control.
I have a file name of a pdf that I want to search for in a folder on a shared network drive \\Share\Projects. The pdf will be in one of the subfolders under projects. I then want to return the entire file path of the pdf into a cell (eg \\Share\Projects\Subfolder\Another subfolder\thisone.pdf).
I have started the code but can't figure out how to search a file system:
Sub InsertPath()
Dim PONumber As String
PONumber = InputBox("PO Number:", "PO Number")
'search for order
Dim myFolder As Folder
Dim myFile As File
'This bit doesn't work
Set myFolder = "\\Share\Projects"
For Each myFile In myFolder.Files
If myFile.Name = "PO" & PONumber & ".pdf" Then
'I have absolutely no idea how to do this bit
End If
Next
End Sub
Am I on the right track or is my code completely wrong?
get list of subdirs in vba
slighly modified the above post.
Public Arr() As String
Public Counter As Long
Sub LoopThroughFilePaths()
Dim myArr
Dim i As Long
Dim j As Long
Dim MyFile As String
Const strPath As String = "C:\Personal\" ' change it as per your needs
myArr = GetSubFolders(strPath)
Application.ScreenUpdating = False
Range("A1:B1") = Array("text file", "path")
For j = LBound(Arr) To UBound(Arr)
MyFile = Dir(myArr(j) & "\*.pdf")
Do While Len(MyFile) <> 0
i = i + 1
Cells(i, 1) = MyFile
Cells(i, 2) = myArr(j)
MyFile = Dir
Loop
Next j
Application.ScreenUpdating = True
End Sub
Function GetSubFolders(RootPath As String)
Dim fso As Object
Dim fld As Object
Dim sf As Object
Dim myArr
Set fso = CreateObject("Scripting.FileSystemObject")
Set fld = fso.GetFolder(RootPath)
For Each sf In fld.SUBFOLDERS
Counter = Counter + 1
ReDim Preserve Arr(Counter)
Arr(Counter) = sf.Path
myArr = GetSubFolders(sf.Path)
Next
GetSubFolders = Arr
Set sf = Nothing
Set fld = Nothing
Set fso = Nothing
End Function
Well, your folder declaration isn't set against a filesystemobject so it can't find the folder. And because it's a network location, you may need to map a network drive first so that it's a secure link.
So here's an updated version of your code.
EDIT - to OP's conditions.
Dim PONumber As String
Sub InsertPath()
PONumber = InputBox("PO Number:", "PO Number")
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim Servershare As String
ServerShare = "S:\"
Dim Directory As Object
Set Directory = fso.GetFolder(ServerShare)
Subfolderstructure Directory
End Sub
Function Subfolderstructure(Directory As Object)
For Each oFldr in Directory.SubFolders
For Each FileName In oFldr.Files
If FileName.Name = "PO" & PONumber & ".pdf" Then
sheets("Sheet1").range("A1").value = ServerShare & "\PO" & PONumber & ".pdf"
Exit For
End If
Next
Dim sbfldrs : Set sbfldrs = ofldr.SubFolders
If isarray(sbfldrs) then
Subfolderstructure ofldr
End if
Next
'Cleanup
Set FileName = Nothing
Set Directory = Nothing
Set fso = Nothing
End Function
I have not tested this code. Try it out and let me know how it works.
I have a list of filenames in one of my workbook. I was wondering if anyone knows how to open the file when the name is not in that list. For example, the list contains names for file “ab”, “bc”, “cd” & “de”. File “ac”, “bd” & “eg” are not in the list, and I only want to open that files so there is no duplication. I know I can just remove the duplication, but it’s time consuming to open files that already exist in the list. I’m new with VBA and I did some research about this topic, but found nothing. I really appreciate anyone that can help me. Thank you!
So here is what I came up so far:
Sub Test1()
Dim File As String
Dim wb As Workbook
Dim wbList As Workbook
Dim filesRange As Range
Dim f As Range
Dim fileName As String
Dim Average As Double
Dim StdDev As Double
Dim OpenNum As Double
Dim Min As Double
Dim Max As Double
Dim wbDestination As Workbook
Const wbPath As String = "C:\Users\10 stop.xlsx"
Const pathToFiles As String = "C:\Users\J\"
File = Dir(pathToFiles, vbDirectory)
Set wbList = Workbooks.Open(wbPath)
Set filesRange = wbList.Sheets("18x17 - 10 mil stop").Range("A:A")
Do While Len(File) > 0
Set f = filesRange.Find(What:=f, LookIn:=xlValues, Lookat:=xlWhole)
If f Is Nothing Then
Set wb = Workbooks.Open(pathToFiles & File)
fileName = ActiveWorkbook.Name
Worksheets(1).Select
Average = Range("B15")
Worksheets(1).Select
StdDev = Range("B16")
Worksheets(1).Select
OpenNum = Range("B13")
Worksheets(1).Select
Min = Range("B17")
Worksheets(1).Select
Max = Range("B18")
Set wbDestination = Workbooks.Open("C:\Users\10 stop.xlsx")
Worksheets(ActiveSheet.Name).Select
Worksheets(ActiveSheet.Name).Range("a1").Select
RowCount = Worksheets(ActiveSheet.Name).Range("a1").CurrentRegion.Rows.Count
With Worksheets(ActiveSheet.Name).Range("a1")
.Offset(RowCount, 0) = fileName
.Offset(RowCount, 1) = Average
.Offset(RowCount, 2) = StdDev
.Offset(RowCount, 3) = OpenNum
.Offset(RowCount, 4) = Min
.Offset(RowCount, 5) = Max
End With
End If
File = Dir()
Loop
End Sub
I got Runtime-error '5': Invalid Procedure Call or Argument on
Set f = filesRange.Find(What:=f, LookIn:=xlValues, Lookat:=xlWhole)
For the files that I want to open and read, I would like to use wildcard "-10_.csv"
I tried many different ways, but all of them gave me blank sheets as result.
I used the 'RecursiveDir' previously, but it's slow and open every files over and over again when I try to update my data.
This is so frustrating :(
Please help!
Added sub-folder searching. Compiled but not tested.
Sub Test1()
Dim wb As Workbook
Dim wbList As Workbook
Dim filesRange As Range
Dim f As Range
Dim wbDestination As Workbook
Dim rw As Range
Dim allFiles As New Collection, File, fName
Const wbPath As String = "C:\Users\10 stop.xlsx"
Const pathToFiles As String = "C:\Users\J\"
Set wbList = Workbooks.Open(wbPath)
Set filesRange = wbList.Sheets("18x17 - 10 mil stop").Range("A:A")
GetFiles pathToFiles, "*-10_.csv", True, allFiles
For Each File In allFiles
fName = FileNameOnly(File)
Set f = filesRange.Find(What:=fName, LookIn:=xlValues, Lookat:=xlWhole)
If f Is Nothing Then
Set wb = Workbooks.Open(File)
'***need to specify sheet name below...
Set rw = wbList.Sheets("sheetname").Cells(Rows.Count, 1) _
.End(xlUp).Offset(1, 0).EntireRow
rw.Cells(1).Value = fName 'or `File` if you want the full path
With wb.Sheets(1)
rw.Cells(2).Value = .Range("B15").Value 'avg
rw.Cells(3).Value = .Range("B16").Value 'stdev
rw.Cells(4).Value = .Range("B13").Value 'opennum
rw.Cells(5).Value = .Range("B17").Value 'min
rw.Cells(6).Value = .Range("B18").Value 'max
End With
wb.Close False 'don't save
End If
Next File
End Sub
'given a path, return only the filename
Function FileNameOnly(sPath)
Dim arr
arr = Split(sPath, "\")
FileNameOnly = arr(UBound(arr))
End Function
Sub GetFiles(StartFolder As String, Pattern As String, _
DoSubfolders As Boolean, ByRef colFiles As Collection)
Dim f As String, sf As String, subF As New Collection, s
If Right(StartFolder, 1) <> "\" Then StartFolder = StartFolder & "\"
f = Dir(StartFolder & Pattern)
Do While Len(f) > 0
colFiles.Add StartFolder & f
f = Dir()
Loop
sf = Dir(StartFolder, vbDirectory)
Do While Len(sf) > 0
If sf <> "." And sf <> ".." Then
If (GetAttr(StartFolder & sf) And vbDirectory) <> 0 Then
subF.Add StartFolder & sf
End If
End If
sf = Dir()
Loop
For Each s In subF
GetFiles CStr(s), Pattern, True, colFiles
Next s
End Sub