I have the following excel spreadsheet, tracker.xls with 2 columns: category and count.
I want to loop through a subdirectory which contains pdf files which match the category column in my spreadsheet.
This is what I've done so far, but my code does not seem to be working:
Sub CV()
Function CVCount()
CategoryArray = Range("A2:A3")
CountArray = Range("B2:B3")
For i = 1 To UBound(CategoryArray)
For j = 1 To UBound(CategoryArray, 2)
'get name of category
Dim Category As String
Category = (myarray(i, j))
FolderPath = Category + "\"
path = FolderPath & "\*.pdf"
Filename = Dir(path)
For k = 1 To UBound(CountArray)
For l = 1 To UBound(CountArray, 2)
'get count
Do While Filename <> ""
count = count + 1
Filename = Dir()
Loop
'assign count to cell
Range("").Value = count
Next k
Next j
Next i
End Function
End Sub
I can't seem to figure out how to assign a count to a cell. Any ideas how to?
You're on the right track, but it's far simpler than that:
Option Explicit
Private Const baseFolder As String = "C:\Users\Hazel\Documents\Personal\Accounts\Childcare\"
Sub countFiles()
Dim path As String
Dim fileName As Variant
Dim count As Integer
Dim i As Integer
i = 1
Do While Range("A" & i + 1).Value <> ""
count = 0
i = i + 1
path = baseFolder & Range("A" & i).Value & "\"
fileName = Dir(path)
Do While fileName <> ""
If UCase$(Right(fileName, 3)) = "PDF" Then count = count + 1
fileName = Dir()
Loop
Range("B" & i).Value = count
Loop
End Sub
Just change the "baseFolder" constant to match your starting directory.
Related
I have a file path in Column A and want to display the count of how many files are between a date range, and if there are any files I want to be able to have a comment on the cell showing the file names and dates.
I have a code that I've gotten help on, but when the code runs it counts all the files in the folder and the comment only appears on the last number in the column.
Sub CreateMouseoverList(Optional FileFilter As String, Optional LowDate As Date, Optional HighDate As Date)
Dim Cell As Range
Dim Ext As Variant
Dim File As Object
Dim FileCnt As Long
Dim Files As Object
Dim Folder As Variant
Dim Item As Variant
Dim List() As Variant
Dim MaxLen As Long
Dim ModDate As Date
Dim m As Long
Dim n As Long
Dim Note As Comment
Dim Text As String
If IsMissing(FileFilter) Then FileFilter = "*.*"
' // Is there is no LowDate then use 1.
If LowDate = 0 Then LowDate = 2
' // If there is no HighDate then use today's date.
If HighDate = 0 Then HighDate = Now()
With CreateObject("Shell.Application")
For Each Cell In Range("A1", Cells(Rows.count, "A").End(xlUp))
FileCnt = 0
ReDim List(1 To 1)
Set Note = Cell.Offset(0, 1).Comment
If Note Is Nothing Then Set Note = Cell.Offset(0, 1).AddComment
Note.Shape.TextFrame.Characters(1, Len(Note.Text)).Delete
Note.Shape.TextFrame.Characters.Font.FontStyle = "regular"
Set Folder = .Namespace(Cell.Value)
If Not Folder Is Nothing Then
Set Files = Folder.Items
For Each Ext In Split(FileFilter, ";")
Files.Filter 64, Ext
Text = vbLf & " " & Ext & " Files | " & vbLf
List(UBound(List)) = Text
n = UBound(List) + 1
ReDim Preserve List(1 To n)
Text = String(Len(Text), "-") & " | " & vbLf
List(UBound(List)) = Text
n = UBound(List) + 1
ReDim Preserve List(1 To n)
Note.Shape.TextFrame.Characters.Font.Name = "Courier New"
Note.Shape.TextFrame.AutoSize = True
For Each File In Files
ModDate = File.ModifyDate
If ModDate >= LowDate And HighDate <= HighDate Then
FileCnt = FileCnt + 1
Text = File.Name & " | " & ModDate & vbLf
List(n) = Text
n = UBound(List) + 1
ReDim Preserve List(1 To n)
If Len(Text) > MaxLen Then MaxLen = Len(Text)
End If
Next File
Next Ext
Cell.Offset(0, 1).Value = FileCnt
Else
Cell.Offset(0, 1).Value = "Folder not found."
End If
Next Cell
End With
For Each Item In List
m = Len(Item)
n = Note.Shape.TextFrame.Characters.count + 1
Item = Split(Item, "|")
If UBound(Item) > -1 Then
Text = Item(0) & String(MaxLen - m, 32) & Item(1)
Note.Shape.TextFrame.Characters(n, Len(Text)).Insert Text
End If
Next Item
End Sub
Sub TestIt()
Call CreateMouseoverList("*.txt;*.xls", "4/1/2019","6/10/2019")
End Sub
I would like to be able to count all the files that are between a date range and display what the files are as well as the count.
I am trying to copy a specific cell and 3 columns from multiple files into a single column on another spreadsheet.
The part called "import" simply allows to select multiple files. The part "Datacopy" should copy the desired values.
Sub import()
Dim oFileDialog As FileDialog
Set oFileDialog = Application.FileDialog(msoFileDialogFilePicker)
oFileDialog.AllowMultiSelect = True
oFileDialog.InitialFileName = "C:\Users\L18938\Desktop\New_folder" ' can set your default directory here
oFileDialog.Show
Dim iCount As Integer
For iCount = 1 To oFileDialog.SelectedItems.Count
Call Datacopy(oFileDialog.SelectedItems(iCount))
Next
End Sub
Public Function Datacopy(strPath As String)
Dim filePath As String
Dim FileNum As Integer
filePath = strPath
Dim startDate As String
If Range("A2").Value <> "" Then
Range("A1").End(xlDown).Offset(1, 0).Select
Else:
Range("A1:A" & Range("A" & Rows.Count).End(xlUp).Row).Offset(1, 0).Select
End If
currentRow = 0
rowNumber = 0
Open filePath For Input As #1
'EOF(1) checks for the end of a file
Do Until EOF(1)
If rowNumber = 0 Then
startDate = lineitems(2)
End If
If rowNumber > 18 And item <> "" Then
ActiveCell.Offset(currentRow, 0) = startDate
ActiveCell.Offset(currentRow, 1) = lineitems(0)
ActiveCell.Offset(currentRow, 2) = lineitems(1)
ActiveCell.Offset(currentRow, 3) = lineitems(2)
currentRow = currentRow + 1
End If
End If
Next item
rowNumber = rowNumber + 1
Loop
Close #1
End Function
When I run it I get the error "sub or function not defined".
The cells I am targeting are:
C1 -> is a date, different in each file, to be copied in column A
Columns A18:A, B18:B, C18:C -> are data to be copied in columns B, C, D respectively.
It is important to copy multiple files, as I have more than 180.
Your problem is "startDate = lineitems(2)". There's nothing in your code that assigns any kind of value to "lineitems".
I want to import multiple csv files at the bottom of an existing table. However, when importing the files, it always excludes the first row of the list of each file. The first row of the list differs from the first row of the spreadsheet because in between there are other rows that are not needed (e.g. titles, empty rows...). Resuming: if I upload 5 files, it miss the first desired row of each of the 5 files.
This is the code:
Private Sub Import_auction_offers_Click()
Dim strSourcePath As String
Dim strFile As String
Dim Cnt As Long
'Change the path to the source folder accordingly
strSourcePath = "C:\Users\L18944\Desktop\example"
If Right(strSourcePath, 1) <> "\" Then strSourcePath = strSourcePath & "\"
strFile = Dir(strSourcePath & "*.csv")
Do While Len(strFile) > 0
Cnt = Cnt + 1
Open strSourcePath & strFile For Input As #1
If Range("F2").Value <> "" Then
Range("F1").End(xlDown).offset(1, 0).Select
Else:
Range("F1:F" & Range("F" & Rows.Count).End(xlUp).Row).offset(1, 0).Select
End If
currentRow = 0
rowNumber = 0
'EOF(1) checks for the end of a file
Do Until EOF(1)
Line Input #1, lineFromFile
fileStr = Split(lineFromFile, vbLf)
Dim item As Variant
For Each item In fileStr
'For item = LBound(fileStr) To UBound(fileStr)
lineitems = Split(item, ";")
'Debug.Print (item)
If rowNumber = 1 Then
startDate = lineitems(6)
End If
If rowNumber > 3 And item <> "" Then
If Not doesOfferExist(CStr(lineitems(2))) Then
ActiveCell.offset(currentRow, 0) = startDate
ActiveCell.offset(currentRow, 1) = lineitems(4)
ActiveCell.offset(currentRow, 2) = lineitems(3)
ActiveCell.offset(currentRow, 3) = CDbl(lineitems(6))
ActiveCell.offset(currentRow, 4) = CDbl(lineitems(7))
ActiveCell.offset(currentRow, 5) = lineitems(8)
ActiveCell.offset(currentRow, 6) = lineitems(1)
ActiveCell.offset(currentRow, 7) = lineitems(2)
ActiveCell.offset(currentRow, 8) = "New"
currentRow = currentRow + 1
End If
End If
rowNumber = rowNumber + 1
Next item
Loop
Close #1
Name strSourcePath & strFile As strSourcePath & strFile
strFile = Dir
Loop
Application.ScreenUpdating = True
If Cnt = 0 Then _
MsgBox "No CSV files were found...", vbExclamation
End Sub
Does anyone understand why it miss the first line of each imported list?
Thank you in advance
I didn't go through your ImportAuctionOffers code, but I'm assuming you are finding the new starting row for each file.
This code will let you pick your files (and set your initial directory). Then loop through all the selected items, calling your ImportAuctionOffers procedure for each file.
Sub test()
Dim oFileDialog As FileDialog
Set oFileDialog = Application.FileDialog(msoFileDialogFilePicker)
oFileDialog.AllowMultiSelect = True
oFileDialog.InitialFileName = "C:\Temp" ' can set your default directory here
oFileDialog.Show
Dim iCount As Integer
For iCount = 1 To oFileDialog.SelectedItems.Count
Call ImportAuctionOffers(oFileDialog.SelectedItems(iCount))
Next
End Sub
Update:
For your second issue: Not reading the first data line is likely due to the if statements with RowNumber.
rowNumber=0
Do ...
if RowNumber = 1 Then ...
if RowNumber > 3 ...
RowNumber = RowNumber + 1
loop
Your code is not going to enter either of your if statements when RowNumber equals 0, 2, or 3. You probably just need to change your > 3 to either > 2, or >= 3.
Here is my code:
Private Sub UserForm_Initialize()
Dim MyFolder As String
Dim MyFile As String
Dim j As Integer
Dim Funds(1000)
CD_Date = Cells(1, 4)
Range("A2").Select
i = 1
Do
Funds(i) = UCase(ActiveCell.Value)
i = i + 1
ActiveCell.Offset(1, 0).Select
Loop Until ActiveCell.Value = ""
MyFolder = "C:\windows\"
r = 0
For k = 1 To i - 1
MyFile = Dir$(MyFolder & "*" & Funds(k) & "*")
Do While MyFile <> ""
datka = FileDateTime(MyFolder & MyFile)
If Format(datka, "yymmdd") = Format(CD_Date, "yymmdd") Then
With UserForm1.ListBox1
.AddItem
.List(r, 0) = Funds(k)
.List(r, 1) = MyFile
r = r + 1
End With
End If
MyFile = Dir$
Loop
Next k
Range("A2").Select
End Sub
Code works perfectly, but it doesn't change dynamically when I move CD_Date for prior day or current - 2. It always add item for entered date and only for first run. When I change date in cell it always return me list from first initialize. It resets when I close file and open it again, each time for different date. Is it possible to modify my code that it will be filling dynamically after I change CD_Date or when someone add file to the folder?? I want to avoid closing and opening macro over and over just to get actual data :(
You could add in a loop to remove all items from the ListBox before the point in your code where items are added to effectively refresh it each time. To do this you are looking for something like:
With UserForm1.ListBox1
For i = 1 to .ListCount
.RemoveItem(0)
Next i
End With
In your code it seems like each time you open the form you only want one item in the ListBox, so although the loop here is unnecessary its a good practice to remember. Try placing this in your module just before you add the item:
Private Sub UserForm_Initialize()
Dim MyFolder As String
Dim MyFile As String
Dim j As Integer
Dim Funds(1000)
CD_Date = Cells(1, 4)
Range("A2").Select
i = 1
Do
Funds(i) = UCase(ActiveCell.Value)
i = i + 1
ActiveCell.Offset(1, 0).Select
Loop Until ActiveCell.Value = ""
MyFolder = "C:\windows\"
r = 0
For k = 1 To i - 1
MyFile = Dir$(MyFolder & "*" & Funds(k) & "*")
Do While MyFile <> ""
datka = FileDateTime(MyFolder & MyFile)
If Format(datka, "yymmdd") = Format(CD_Date, "yymmdd") Then
With UserForm1.ListBox1
For i = 1 to .ListCount 'Here
.RemoveItem(0)
Next i
.AddItem
.List(r, 0) = Funds(k)
.List(r, 1) = MyFile
r = r + 1
End With
End If
MyFile = Dir$
Loop
Next k
Range("A2").Select
End Sub
IO want to check all the edf files at the path main directory/ABC*/Y/XY*/*.edf and then check the files for a specific phrase and if found check for another phrase and so on and then fill the data in the spreadsheet. I have tried to achieve this through three methods but was stuck at some point in every method. Is it possible for anyone of you to go through the code and tell me where I am wrong and which the best approach if any. As the misconception created by my previous questions I don't want anyone to write code for me. I've started working on vba for three days and I've 5 days to complete this project. That's why I'd be grateful if anyone could have a look and tell me where I'm going wrong.
Approach 1 through simple directory command
In this First loop for FCS* is working great but then the second loop doesn't work at all and gives run-time error at the first iteration. I know this is not a good approach but in case any other doesn't work.
Sub Iterate_Folders()
Dim ctr As Integer
Dim ctr1 As Integer
ctr = 1
ctr1 = 1
Paths = "C:\Users\sobiakanwal\Downloads\QSHWRA\QSHWRA\ " ' Path should always contain a '\' at end
FirstDir = Dir(Paths, vbDirectory) ' Retrieving the first entry.
Do Until FirstDir = "" ' Start the loop.
If (FirstDir Like "FCS*") Then
ActiveSheet.Cells(ctr, 15).Value = Paths & FirstDir
Path1 = Paths & FirstDir & "\FUNCTION_BLOCK\DR*"
ActiveSheet.Cells(ctr, 20).Value = Path1
'ActiveSheet.Cells(ctr, 25).Value = SecondDir
SecondDir = Dir(Path1, vbDirectory)
Do While SecondDir = ""
ActiveSheet.Cells(ctr, 30).Value = "Hi"
If (True) Then
ctr1 = ctr1 + 1
End If
SecondDir = Dir()
Loop
ctr = ctr + 1
Else
End If
FirstDir = Dir() ' Getting next entry.
Loop
MsgBox (ctr1)
End Sub
Approach 2 through Recursion
I found the basic code for this in a tutorial and then edited it somewhat to my advantage. This doesn't work generically but gives the right answer in somewhat hard-coded manner. But I want you to check just the point where I'm stuck in the recursion function where I need to add the file handling code.
Public temp() As String
Public Count As Integer
Function ListFiles(FolderPath As String)
Dim myFile As String, text As String, textline As String, posLat As Integer, posLong As Integer
Dim k As Long, i As Long
ReDim temp(2, 0)
Count = 1
If Right(FolderPath, 1) <> "\" Then
FolderPath = FolderPath & "\"
End If
Recursive FolderPath
k = Range(Application.Caller.Address).Rows.Count
If k < UBound(temp, 2) Then
MsgBox "There are more rows, extend user defined function"
Else
For i = UBound(temp, 2) To k
ReDim Preserve temp(UBound(temp, 1), i)
temp(0, i) = ""
temp(1, i) = ""
temp(2, i) = ""
Next i
End If
ListFiles = Application.Transpose(temp)
ReDim temp(0)
End Function
Function Recursive(FolderPath As String)
Dim strFilename As String
Dim strFileContent As String
Dim iFile As Integer
Dim fileName As String, textData As String, textRow As String, fileNo As Integer
Dim Value As String, Folders() As String
Dim Folder As Variant, a As Long
Dim Right_FolderPath As String
ReDim Folders(0)
If Right(FolderPath, 2) = "\\" Then Exit Function
Value = Dir(FolderPath, &H10)
Do Until Value = ""
If Value = "." Or Value = ".." Then
Else
If GetAttr(FolderPath & Value) = 16 Then
Folders(UBound(Folders)) = Value
ReDim Preserve Folders(UBound(Folders) + 1)
Else
If Right(Value, 4) = ".edf" Then
If Count = 4 Then
Right_FolderPath = Right(FolderPath, 7)
If Left(Right_FolderPath, 2) = "DR" Then
strFilename = FolderPath & Value
iFile = FreeFile
Open strFilename For Input As #iFile
strFileContent = Input(LOF(iFile), iFile)
Close #iFile
If InStr(1, strFileContent, "hihowareyou") <> 0 Then
ActiveSheet.Cells(1, 1) = strFilename
longLoc = InStr(1, strFileContent, "Longitude:")
If longLoc <> 0 Then
ActiveSheet.Cells(1, 2) = Mid(strFleContent, longLoc + Len("Longitude:"), 10)
End If
End If
''''Here it goes all wrong
'myFile = FolderPath & Value
'myFile = Application.GetOpenFilename()
'fileNo = FreeFile 'Get first free file number
'Open fileName For Input As #fileNo
'Do While Not EOF(fileNo)
' Line Input #fileNo, textRow
' textData = textData & textRow
'Loop
'Close #fileNo
'posLat = InStr(text, "ff-ai")
'If Not posLat = vbNullString Then
' temp(0, UBound(temp, 2)) = Value
'End If
temp(0, UBound(temp, 2)) = FolderPath
temp(1, UBound(temp, 2)) = Value
temp(2, UBound(temp, 2)) = Count ' FileLen(FolderPath & Value)
ReDim Preserve temp(UBound(temp, 1), UBound(temp, 2) + 1)
End If
End If
End If
End If
End If
Value = Dir
Loop
For Each Folder In Folders
Count = Count + 1
Recursive FolderPath & Folder & "\"
Count = Count - 1
Next Folder
End Function
The Third Approach By Dictionary Object
This was suggested by someone on Stock Overflow and worked right for him but not for me. I don't know vba enough to debug it.
Sub build_FolderLevels(dFMs As Scripting.Dictionary, _
Optional sFM As String = "", _
Optional iFLDR As Long = 0)
Dim d As Long, fp As String, vFMs As Variant
If CBool(dFMs.Count) Then
vFMs = dFMs.Keys
For d = LBound(vFMs) To UBound(vFMs)
vFMs(d) = vFMs(d)
Next d
Else
vFMs = Array(sFM)
End If
dFMs.RemoveAll
For d = LBound(vFMs) To UBound(vFMs)
fp = Dir(vFMs(d), iFLDR)
Do While CBool(Len(fp))
dFMs.Add Key:=Left(vFMs(d), InStrRev(vFMs(d), Chr(92))) & fp, _
Item:=iFLDR
fp = Dir
Loop
Next d
End Sub
Sub main()
Dim fm As Long, sFM As String, vFMs As Variant, sMASK As String
Dim fn As Variant, dFNs As New Scripting.Dictionary
sFM = Environ("TMP") & "\QSHWRA\FCS*\FUNCTION_BLOCK\DR*\*.edf"
If UBound(Split(sFM, Chr(42))) < 2 Then Exit Sub '<~~possibly adjust this safety
sFM = Replace(sFM, "/", "\")
vFMs = Split(sFM, Chr(92))
sMASK = vFMs(LBound(vFMs))
For fm = LBound(vFMs) + 1 To UBound(vFMs)
sMASK = Join(Array(sMASK, vFMs(fm)), Chr(92))
If CBool(InStr(1, vFMs(fm), Chr(42))) Or fm = UBound(vFMs) Then
build_FolderLevels dFNs, sFM:=sMASK, iFLDR:=Abs((fm < UBound(vFMs)) * vbDirectory)
sMASK = vbNullString
End If
Next fm
'list the files
For Each fn In dFNs
Debug.Print "from dict: " & fn
Next fn
dFNs.RemoveAll: Set dFNs = Nothing
End Sub
I would suggest you go through all the subfolders below main directory, and just collect the files that meet your criteria. I'd probably use the WindowsShell with something like Dir MainFolder\*.edf /B /S (bare format and recursion switches set) and just save or collect those files that are in desired subfolders. But you could also do something similar with DIR or the FileSystemObject and recursion.