Folder Access denied when access was fine before - file

I have a program that scans through a directory and just lists the folders within it. This has been working fine, but now for some reason it is coming up with an access denied error.
I have checked file permissions, all is fine, changed user password to ensure it has not expired. Even created a dummy directory, but the program states it can't even access that. Tried running the program as administrator, but still fails.
I have attached the code , I just don't know what has changed for this error to suddenly appear on any folder it tries to access.
The line throwing the access error is Using file2 As New IO.FileStream(foldername, IO.FileMode.Open)
I have tried the following
Created a test folder with full permissions
Changed user password under which the program runs
Created a brand new project and re-entered the code
Executed program while logged on with an administrators account.
Updated visual studio with latest updates.
Imports System.ComponentModel
Imports System.Text
Imports System.IO
Imports System.IO.Compression
Partial Public Class Form1
Public SQL As New SQLControl
Public Sub New()
InitializeComponent()
End Sub
Private Sub btn_analysis_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles btn_analysis.ItemClick
Dim fileEx As String
Dim sqltxt As String
Dim ProtectedFileFlip As String
ProtectedFileFlip = "jigsawdummyvalue"
Dim FolderFlip As String
FolderFlip = "jigsawdummyvalue"
Dim FilePathCount As Integer
FilePathCount = 1
Dim FilesCount As Integer
FilesCount = 1
Dim DFilesCount As Integer
DFilesCount = 1
Dim TrueRec As Boolean
Dim FileExt As String
Dim ProtectedFolderCount As Integer
Dim ProtectedFileCount As Integer
Dim FileDeletion As Integer
Dim yy As Integer
Dim xx As Integer
Dim aa As Integer
TrueRec = False
FilePathCount = 1
FilesCount = 1
'Load Protected File Paths
sqltxt = "SELECT * FROM FilePath WHERE Action = 'Retain'"
sqltxt = sqltxt.Replace("""", "'")
SQL.ExecQuery(sqltxt)
Dim ProtectedPath(SQL.RecordCount)
For Each r As DataRow In SQL.DBDT.Rows
ProtectedPath(FilePathCount) = r.ItemArray(1)
FilePathCount = FilePathCount + 1
Next
'Load File Paths to delete
sqltxt = "SELECT * FROM FilePath WHERE Action = 'Delete'"
sqltxt = sqltxt.Replace("""", "'")
SQL.ExecQuery(sqltxt)
Dim RemoveFiles(SQL.RecordCount)
For Each r As DataRow In SQL.DBDT.Rows
RemoveFiles(DFilesCount) = r.ItemArray(1)
DFilesCount = DFilesCount + 1
Next
'Load Protected File Extensions
sqltxt = "SELECT * FROM Definitions"
sqltxt = sqltxt.Replace("""", "'")
SQL.ExecQuery(sqltxt)
Dim ProtectedFile(SQL.RecordCount)
For Each r As DataRow In SQL.DBDT.Rows
ProtectedFile(FilesCount) = r.ItemArray(6)
FilesCount = FilesCount + 1
Next
'Create file output header
ListBox1.Items.Add("JIGSAW FILE ANALYSIS UTILITY VERSION 1.0.0")
'ListBox1.Items.Add("File Analysis commenced of " & foldername)
ListBox1.Items.Add("Analysis commenced at " & Now())
ListBox1.Items.Add("Loaded " & FilePathCount - 1 & " protected file path definitions.")
ListBox1.Items.Add("Loaded " & FilesCount - 1 & " protected file extention definitions.")
ListBox1.Items.Add("Loaded " & DFilesCount - 1 & " file path deletion definitions.")
ListBox1.Items.Add("----------------------------------------------------------------")
Refresh()
'Dim files() As String = Directory.GetFiles(foldername, "*.*", SearchOption.AllDirectories)
'Dim abc As Integer = Directory.GetFiles(foldername, ".", SearchOption.AllDirectories).Count() 'THIS RETURNS 217
'Dim filecount As Integer = IO.Directory.GetFiles(foldername, "*", SearchOption.AllDirectories).Length 'THIS SHOULD RETURN 222 AS REPORTED BY WINDOWS
'Try
Const foldername = "C:\justtest"
Using file2 As New IO.FileStream(foldername, IO.FileMode.Open)
fileEx = file2.Name
'My.Computer.FileSystem.WriteAllText(foldername & "Analysis", fileEx, True)
aa = aa + 1
For x = 1 To DFilesCount - 1
If fileEx.Contains(RemoveFiles(x)) = True And Not fileEx.Contains(FolderFlip) Then
'If fileEx.Contains(RemoveFiles(x)) = True Then
ListBox1.Items.Add(fileEx & " Located in " & RemoveFiles(x) & " contents of folder will be removed.")
FolderFlip = RemoveFiles(x)
GoTo mole
End If
If fileEx.Contains(RemoveFiles(x)) = True And fileEx.Contains(FolderFlip) = True Then
GoTo mole
End If
Next
For x = 1 To FilePathCount - 1
If fileEx.Contains(ProtectedPath(x)) = True And Not fileEx.Contains(ProtectedFileFlip) Then
ListBox1.Items.Add(fileEx & " Located in " & ProtectedPath(x) & " ignored, protected folder, all files will be archived.")
ProtectedFolderCount = ProtectedFolderCount + 1
ProtectedFileFlip = ProtectedPath(x)
TrueRec = True
GoTo mole
End If
If fileEx.Contains(ProtectedPath(x)) = True And fileEx.Contains(ProtectedFileFlip) = True Then
GoTo mole
End If
duck:
Next x
For x = 1 To FilesCount
'need to extract just the file extentions
yy = 0
xx = 1
For y = 1 To Len(fileEx)
FileExt = Mid(fileEx, Len(fileEx) - yy, xx)
If FileExt.Contains(".") Then
FileExt = Mid(fileEx, Len(fileEx) - (yy - 1), xx - 1)
GoTo rabbit
End If
yy = yy + 1
xx = xx + 1
Next y
rabbit:
For gg = 1 To FilesCount - 1
'we need to check the wild cards such as Ex*
If FileExt = ProtectedFile(gg) Then
ListBox1.Items.Add(fileEx & " ignored, protected file. File will be archived.")
ProtectedFileCount = ProtectedFileCount + 1
TrueRec = True
GoTo frog
End If
Next gg
Next x
Refresh()
End Using
'Catch
' ListBox1.Items.Add("Unable to report on file.")
' aa = aa + 1
'End Try
frog:
If TrueRec = False Then
ListBox1.Items.Add(fileEx & " file will be deleted prior to archiving process.")
FileDeletion = FileDeletion + 1
End If
TrueRec = False
Refresh()
mole:
Refresh()
ListBox1.Items.Add("----------------------------------------------------------------")
ListBox1.Items.Add("SUMMARY INFORMATION---------------------------------------------")
ListBox1.Items.Add("Analysis completed at " & Now())
ListBox1.Items.Add("Number of protected folders identified--- " & ProtectedFolderCount)
ListBox1.Items.Add("Number of protected files identified------ " & ProtectedFileCount)
ListBox1.Items.Add("Number of files which will be deleted----- " & FileDeletion)
ListBox1.Items.Add("Number of files scanned ------------------ " & aa)
MsgBox("Scan completed", vbOKOnly, "Completed")
End Sub
End Class

Related

Best way to interpret HTML Response and paste on Worksheet

I have a URL that returns a ton of information that I need to break apart into rows/columns etc.
So far I have been able to get the .responsetext and then use Split to break it down, but I'm wondering best approach for getting this data onto spreadsheet as I'm about to do more "Split" and I feel like there is a better way using perhaps Arrays?
Macro:
Sub TEstHTML()
Dim URLStr As String
URLStr = "PrivateURL"
'< VBE > Tools > References > Microsoft Scripting Runtime & Microsoft XML, V6.0
Dim xhr As MSXML2.XMLHTTP60
Dim table As MSHTML.HTMLTable
Dim tableCells As MSHTML.IHTMLElementCollection
Set xhr = New MSXML2.XMLHTTP60
With xhr
.Open "GET", URLStr, False
.send
If .readyState = 4 And .status = 200 Then
Set doc = New MSHTML.HTMLDocument
doc.body.innerHTML = .responseText
Debug.Print doc.body.innerHTML
Stop
Else
Debug.Print "Error" & vbNewLine & "Ready state: " & .readyState & vbNewLine & "HTTP request status: " & .status
End If
End With
Dim SplitArr() As String
SplitArr = Split(doc.body.innerHTML, "{")
Debug.Print SplitArr(1)
Stop
End Sub
The page sends back a lot of data formatted like so:
{"ClientCode":"CLICODE","ClientName":"MyClient","ContractNumber":"2021-1",...}
Which the Split function returns:
"ClientCode":"CLICODE","ClientName":"MyClient","ContractNumber":"2021-1",...
I need to turn this into Colum Headers ClientCode & ClientName & ContractNumber and then paste the values one SplitArr(i) at a time. Note there are many column headers I'd like this to not be hardcoded ideally, but if needed I can make the column headers and then paste information somehow.
Update:
I'm not sure if I'm doing it wrong, or this data is/isn't JSON but this tool works great. I did have to make a function to "clean" the strings though. Here is what I ended up with..
Sub Testing()
Dim URLStr As String
URLStr = "URL"
Dim HTMLDoc As MSHTML.HTMLDocument
Set HTMLDoc = New MSHTML.HTMLDocument
Set HTMLDoc = Get_HTMLDocument(URLStr)
Dim HTMLDocStr As String
HTMLDocStr = HTMLDoc.body.innerHTML
HTMLDocStr = ConvertToJsonClear(HTMLDocStr)
Dim SplitArr() As String, Parsed As Dictionary, k, l As Long
SplitArr = Split(HTMLDocStr, "{")
For X = 1 To UBound(SplitArr) Step 1
l = 0
HTMLDocStr = ConvertToJsonClear(SplitArr(X))
Set Parsed = JsonConverter.ParseJson(HTMLDocStr)
For Each k In Parsed.Keys
l = l + 1
If X = 1 Then
Cells(1, l).Value = k
End If
Cells(X + 1, l).Value = Parsed(k)
'Debug.Print k & " = "; Parsed(k)
Next
'Stop
Next X
Stop
End Sub
Public Function ConvertToJsonClear(JSonStr As String) As String
JSonStr = JsonConverter.ConvertToJson(JSonStr)
JSonStr = Replace(JSonStr, "[", "")
JSonStr = Replace(JSonStr, "]", "")
JSonStr = Replace(JSonStr, "\", "")
If Left(JSonStr, 1) = Chr(34) Then
'Stop
JSonStr = Right(JSonStr, Len(JSonStr) - 1)
End If
If Left(JSonStr, 1) <> "{" Then
'Stop
JSonStr = "{" & JSonStr
End If
If Right(JSonStr, 3) = "},""" Then
'Stop
'Debug.Print Right(JSonStr, 3)
'Stop
JSonStr = Left(JSonStr, Len(JSonStr) - 2) & Chr(34)
End If
If Right(JSonStr, 1) = "," Then
'Stop
JSonStr = Left(JSonStr, Len(JSonStr) - 1)
End If
ConvertToJsonClear = JSonStr
'Debug.Print ConvertToJsonClear
End Function
I don't have my real data in front of me, but I tackled this a home with a homemade TestStr. The VBA-JSON parser linked in OP Comments by #TimWilliams worked great with a bit of string manipulation. I'll have to play around with real data and perhaps clean it up, but this works for now!
Public Sub JsonTest()
Dim TestStr As String, SplitArr() As String, k, I As Long
TestStr = "{""CC"":""TestA"",""DD"":""RESA"",""ZZ"":""RESAA""},{""CC"":""TestB"",""DD"":""RESB"",""ZZ"":""RESBB""}"
SplitArr = Split(TestStr, "{")
For I = 1 To UBound(SplitArr) Step 1
TestStr = JsonConverter.ConvertToJson("{" & SplitArr(I))
TestStr = Left(TestStr, Len(TestStr) - 1)
TestStr = Right(TestStr, Len(TestStr) - 1)
TestStr = Replace(TestStr, "\", "")
'Debug.Print TestStr
'Stop
Set Parsed = JsonConverter.ParseJson(TestStr)
For Each k In Parsed.Keys
Debug.Print k & " = " & Parsed(k)
'Stop
Next
Next
End Sub

Remove delimiters from Join() Function in EXcel VBA

I am a novice programmer and I'm building a form via VBA for excel where the user will input employee's time sheet and their initials via 16 text box's in the form. The text boxes data are stored to a string array. The code is:
Dim initials(15) As String
initials(0) = TB_Initials_1
initials(1) = TB_Initials_2
initials(2) = TB_Initials_3
...
initials(15) = TB_Initials_15
After using the find function and referencing some data from a one excel sheet, I use
ActiveCell.Offset(0, 2).Value = Join(initials, ".")
to output the following
"js.rs.............." to the active cell in a different excel sheet, (I only entered 2 of the 16 input boxes, hence there's two initials. JS.RS
The trailing .............. is what I want to remove. this will be imported into a Database later via the excel sheet.
How can I remove the xtras ".........'s at the end of the string? I have tried the "Trim()" function, but that does not work in my case. Everything i've tried online does not seem to work either or is referencing items from a work book, not a text box.
Any help is appreciated.
The entire code is below:
Option Explicit
'Variable declaration
Dim startTime(15), endTime(15), ST_Finish_Date As Date
Dim totalmin(15), Total_min, Total_Cost, Rate(15), Line_cost(15), Cost_Per_Part As String
Dim initials(15) As String
Dim i, ii As Integer
Dim Found_ini(15) As Range
Dim Found As Range 'returned value from find
Dim TBtraveller_value As String 'text box traveller value
Dim Found2 As Range 'store part code range
Dim TBDESC As Range ' Returned value from 2nd search
Dim BL_Find_Check As Boolean
Private Sub CB_Write_Click()
create_csv
End Sub
Private Sub Close_Form_Click()
Unload Traveller_Entry
End Sub
'still need to make this for every start / stop time text box.
Private Sub TB_Time_Start_1_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
Dim myvar As String
If Not Me.TB_Time_Start_1 Like "??:??" Then
MsgBox "Please use format 'HH:MM'"
Cancel = True
Exit Sub
End If
myvar = Format(Me.TB_Time_Start_1, "hh:mm")
Me.TB_Time_Start_1 = myvar
End Sub
Public Sub travellerNUM_TextBox_Exit(ByVal Cancel As MSForms.ReturnBoolean)
Workbooks("Traveller entryxlsm.xlsm").Activate
TBtraveller_value = travellerNUM_TextBox.Value
If TBtraveller_value = "" Then
MsgBox ("Enter a Shop Traveller Number!")
Exit Sub
Else
TBtraveller_value = travellerNUM_TextBox.Value
Set Found = Sheets("woss").Range("A:A").Find(what:=TBtraveller_value, lookat:=xlWhole)
If Found Is Nothing Then
MsgBox (TBtraveller_value & " Not Found!")
Exit Sub
Else
Part_Code_BOX.Value = Found.Offset(0, 1) 'enters the info into the Part Code Box.
Set Found2 = Found.Offset(0, 1)
End If
If Part_Code_BOX = "" Then
MsgBox ("Traveller number " & TBtraveller_value & " has no part code associated with it." & vbCrLf & "Check Work Order Spread Sheet is FULLY Complete.")
BL_Find_Check = True
Exit Sub
End If
Set TBDESC = Sheets("ProductList").Range("B:B").Find(what:=Found2, lookat:=xlPart)
If TBDESC Is Nothing Then
MsgBox (" Dscription Not Found!")
Else
Desc_Box = TBDESC.Offset(0, 1) 'enters the description into the description Box.
FinishDate_Box = Found.Offset(0, 8) 'enters the finish date into the finish date Box.
Employee = Found.Offset(0, 2) 'enters the Employee name into the employee name Box.
End If
End If
End Sub
Public Sub CB_POST_Click()
On Error Resume Next
startTime(0) = TB_Time_Start_1.Value
startTime(1) = TB_Time_Start_2.Value
startTime(2) = TB_Time_Start_3.Value
startTime(3) = TB_Time_Start_4.Value
startTime(4) = TB_Time_Start_5.Value
startTime(5) = TB_Time_Start_6.Value
startTime(6) = TB_Time_Start_7.Value
startTime(7) = TB_Time_Start_8.Value
startTime(8) = TB_Time_Start_9.Value
startTime(9) = TB_Time_Start_10.Value
startTime(10) = TB_Time_Start_11.Value
startTime(11) = TB_Time_Start_12.Value
startTime(12) = TB_Time_Start_13.Value
startTime(13) = TB_Time_Start_14.Value
startTime(14) = TB_Time_Start_15.Value
startTime(15) = TB_Time_Start_16.Value
endTime(0) = TB_Time_Stop_1.Value
endTime(1) = TB_Time_Stop_2.Value
endTime(2) = TB_Time_Stop_3.Value
endTime(3) = TB_Time_Stop_4.Value
endTime(4) = TB_Time_Stop_5.Value
endTime(5) = TB_Time_Stop_6.Value
endTime(6) = TB_Time_Stop_7.Value
endTime(7) = TB_Time_Stop_8.Value
endTime(8) = TB_Time_Stop_9.Value
endTime(9) = TB_Time_Stop_10.Value
endTime(10) = TB_Time_Stop_11.Value
endTime(11) = TB_Time_Stop_12.Value
endTime(12) = TB_Time_Stop_13.Value
endTime(13) = TB_Time_Stop_14.Value
endTime(14) = TB_Time_Stop_15.Value
endTime(15) = TB_Time_Stop_16.Value
initials(0) = TB_Initials_1
initials(1) = TB_Initials_2
initials(2) = TB_Initials_3
initials(3) = TB_Initials_4
initials(4) = TB_Initials_5
initials(5) = TB_Initials_6
initials(6) = TB_Initials_7
initials(7) = TB_Initials_8
initials(8) = TB_Initials_9
initials(9) = TB_Initials_10
initials(10) = TB_Initials_11
initials(11) = TB_Initials_12
initials(12) = TB_Initials_13
initials(13) = TB_Initials_14
initials(14) = TB_Initials_15
initials(15) = TB_Initials_16
For i = LBound(initials) To UBound(initials)
Set Found_ini(i) = Sheets("rate").Range("B:B").Find(what:=initials(i), lookat:=xlWhole)
Rate(i) = Found_ini(i).Offset(0, 1) 'finds rate for given initials
totalmin(i) = DateDiff("N", startTime(i), endTime(i))
If Found_ini(i) Is Nothing Then
MsgBox (initials(i) & " Not Found! Update Employee Database.")
Exit Sub
'If IsEmpty(Found_ini(i)) = False And IsEmpty(startTime(i)) = True And IsEmpty(endTime(i)) = True Then
'MsgBox "Enter Some Initials, None Found"
Exit Sub
End If
Next
For ii = LBound(totalmin) To UBound(totalmin)
Line_cost(ii) = totalmin(ii) / 60 * Rate(ii)
Next
Total_min = Application.WorksheetFunction.Sum(totalmin)
Total_Cost = Application.WorksheetFunction.Sum(Line_cost)
Cost_Per_Part = Total_Cost / TextBOX_QTYBUILT
If Total_min = 0 Then
MsgBox (" Enter Some Time!")
ElseIf Total_min < 0 Then
MsgBox ("Time is NEGATIVE. Check Entered Times.")
End If
If BL_Find_Check = False Then
MsgBox "The number of minutes between two Times : " & Total_min & vbNewLine & "total cost: " & Total_Cost _
& vbNewLine & "cost Per Part " & Cost_Per_Part, vbInformation, "Minutes Between Two Times"
Sheets("test").Select
Range("A1048576").Select
ActiveCell.End(xlUp).Select
ActiveCell.Offset(1, 0).Select
ActiveCell.Offset(0, 0).Value = FinishDate_Box 'Traveller finish Date
ActiveCell.Offset(0, 1).Value = TBtraveller_value 'Traveller Number
ActiveCell.Offset(0, 2).Value = Join(initials, ".") 'Traveller Employee Given to
ActiveCell.Offset(0, 3).Value = Part_Code_BOX.Value ' part number
ActiveCell.Offset(0, 4).Value = Total_Cost ' traveller total cost
ActiveCell.Offset(0, 5).Value = Cost_Per_Part 'Traveller cost per part
End If
End Sub
Sub create_csv()
Dim FileName As String
Dim PathName As String
Dim ws As Worksheet
Set ws = ActiveWorkbook.Sheets("test")
FileName = "CSV_Output_R1.csv"
PathName = Application.ActiveWorkbook.Path
ws.Copy
ActiveWorkbook.SaveAs FileName:=PathName & "\" & FileName, _
FileFormat:=xlCSV, CreateBackup:=False
End Sub
Thank you,
You can use WorksheetFunction.TextJoin() in Excel2019+ in one string:
ActiveCell.Offset(0, 2).Value = WorksheetFunction.TextJoin(".", True, initials)
A small example for comparison:
Sub test1()
Dim arr(1 To 15)
For i = 1 To 15
arr(i) = IIf(Rnd() > 0.7, "TXT", "")
Next
Debug.Print "With Join(): " & Join(arr, ".")
Debug.Print "With TextJoin(): " & WorksheetFunction.TextJoin(".", True, arr)
End Sub
Output
With Join(): ..TXT........TXT..TXT..
With TextJoin(): TXT.TXT.TXT
Here is a function that I just made to trim empty elements off the end of your array:
Function TrimArray(ByRef StringArray() As String) As String()
'This function removes trailing empty elements from arrays
'Searching from the last element backwards until a non-blank is found
Dim i As Long
For i = UBound(StringArray) To LBound(StringArray) Step -1
If StringArray(i) <> "" Then Exit For
Next i
If i < LBound(StringArray) Then i = LBound(StringArray)
'Creating an array with the correct size to hold the non-blank elements
Dim OutArr() As String
OutArr = StringArray
ReDim Preserve OutArr(LBound(StringArray) To i)
TrimArray = OutArr
End Function
You would use it like so:
Dim Output() As String
Output = TrimArray(initials)
MsgBox Join(Output, ".") & "."
You could build it like this instead of using Join():
ActiveCell.Offset(0, 2).Value = initials(0)
For Counter = 1 To 15
If initials(Counter) <> "" Then
ActiveCell.Offset(0, 2).Value = ActiveCell.Offset(0, 2).Value + "." + initials(Counter)
End If
Next Counter

Feeding multiple values in a loop to an array with VBA

Scenario: I am reading through folders and subfolders of a directory, if the found file is an ".xls" it opens. I then run another condition that, if true, will try to pass some values to the array.
Objective: I am defining my array without dimensions, because I don't know how many files will feed into it. For each file that fulfills the conditions, I am trying to get 3 values (name, path, date) and add to the array. Each file would be added to a new row of the array.
Ex. of array:
If 3 files fulfill the condition...
name1 path1 date1
name2 path2 date2
name3 path3 date3
Issue: when I run, I get a subscript out of range error when I try to pass the values to the array. How can I fix that?
Code1: This starts the loop through folders
Public Sub getInputFileInfo()
Dim FileSystem As Object
Dim HostFolder As String
' User selects where to search for files:
HostFolder = GetFolder()
Set FileSystem = CreateObject("Scripting.FileSystemObject")
DoFolder FileSystem.GetFolder(HostFolder)
End Sub
Code2: This gets the data:
Public Sub DoFolder(Folder)
Dim strFilename As String, filePath As String
Dim dateC As Date
Dim oFS As Object
Dim outputarray() As Variant
Dim ii As Long, lRow As Long, lCol As Long, lRow2 As Long
Dim w2, w As Workbook
Set w = ThisWorkbook
ii = 1
Dim SubFolder
For Each SubFolder In Folder.SubFolders
DoFolder SubFolder
Next SubFolder
Dim File
For Each File In Folder.Files
Set oFS = CreateObject("Scripting.FileSystemObject")
'Set w2 = File
filePath = File.Path
strFilename = File.Name
dateC = File.dateCreated
If InStr(LCase(File.Path), LCase("xls")) <> 0 Then
Set w2 = Workbooks.Open(filePath)
For lRow2 = 1 To w2.Sheets(1).Cells(Rows.Count, 1).End(xlUp).Row
If w2.Sheets(1).Range("A" & lRow2).Value = "Test Name" Then
outputarray(0, ii) = strFilename ' THE ERROR STARTS HERE
outputarray(1, ii) = filePath
outputarray(2, ii) = dateC
ii = ii + 1
End If
Next lRow2
w2.Close False
End If
Set oFS = Nothing
Next File
For lRow = 1 To UBound(outputarray, 1)
For lCol = 1 To UBound(outputarray, 2)
w.Sheets("ControlSheet").Cells(lRow, lCol).Value = outputarray(lRow, lCol).Value
Next lCol
Next lRow
End Sub
I would use a dictionary and a "class" like in the following example.
The class fInfo looks like that
Option Explicit
Public fileName As String
Public filepath As String
Public fileDateCreated As Date
Then you could test it like that
Sub AnExample()
Dim dict As New Scripting.Dictionary
Dim fInfo As fileInfo
Dim filepath As String
Dim strFilename As String
Dim dateC As Date
Dim i As Long
For i = 1 To 2
filepath = "Path\" & i
strFilename = "Name" & i
dateC = Now + 1
Set fInfo = New fileInfo
With fInfo
.filepath = filepath
.fileName = strFilename
.fileDateCreated = dateC
End With
dict.Add i, fInfo
Next i
For i = 1 To dict.Count
With dict.Item(i)
Debug.Print .filepath, .fileName, .fileDateCreated
End With
Next i
End Sub
In your code maybe like that
For lRow2 = 1 To w2.Sheets(1).Cells(Rows.Count, 1).End(xlUp).Row
If w2.Sheets(1).Range("A" & lRow2).Value = "Test Name" Then
Set fInfo = New fileInfo
With fInfo
.filepath = filepath
.fileName = strFilename
.fileDateCreated = dateC
End With
dict.Add ii, fInfo
' outputarray(0, ii) = strFilename ' THE ERROR STARTS HERE
' outputarray(1, ii) = filepath
' outputarray(2, ii) = dateC
' ii = ii + 1
End If
Next lRow2
try with these steps:
1) temporarily size the array to the maximum number of files
2) keep track of found files
3) finally resize array to actual number of found files
As follows (I only show relevant snippet):
ii = -1 '<<< initialize the counter fo found files to -1: it's more convenient for its subsequent updating and usage
ReDim outputarray(0 To 2, 0 To Folder.Files.Count) As Variant ' <<< temporarily size the array to the maximum number of files
For Each File In Folder.Files
Set oFS = CreateObject("Scripting.FileSystemObject")
'Set w2 = File
filePath = File.Path
strFilename = File.Name
dateC = File.dateCreated
If InStr(LCase(File.Path), LCase("xls")) <> 0 Then
Set w2 = Workbooks.Open(filePath)
For lRow2 = 1 To w2.Sheets(1).Cells(Rows.Count, 1).End(xlUp).Row
If w2.Sheets(1).Range("A" & lRow2).Value = "Test Name" Then
ii = ii + 1 '<<< update the number of found files
outputarray(0, ii) = strFilename
outputarray(1, ii) = filePath
outputarray(2, ii) = dateC
End If
Next lRow2
w2.Close False
End If
Set oFS = Nothing
Next File
ReDim Preserve outputarray(0 To 2, 0 To ii) As Variant '<<< finally resize array to actual number of found files
edit
BTW you can avoid the double nested writing loops and use a one shot statement:
w.Sheets("ControlSheet").Range("A1").Resize(UBound(outputarray, 1) + 1, UBound(outputarray, 2) + 1).Value = outputarray

VBA Directory File Search using list within Excel

I'm currently trying to edit a macro a colleague of mine currently uses, the script currently opens a message box that allows you to enter in a string, which is then searched for and results are pasted into the workbook. I would like to change this so it searches for a list already within the spreadsheet, and then for the results to be pasted on the next worksheet. I'm not sure if this is actually possible or not, which is where my main struggle is. Below is the current code, I assume all that is needed is for the variable range to be placed in that stars "msg = "Enter file name and Extension"
Sub Filesearch()
Dim myDir As String, temp(), myList, myExtension As String
Dim SearchSubFolders As Boolean, Rtn As Integer, msg As String
With Application.FileDialog(msoFileDialogFolderPicker)
If .Show Then
myDir = .SelectedItems(1)
End If
End With
msg = "Enter File name and Extension" & vbLf & "following wild" & _
" cards can be used" & vbLf & "* # ?"
myExtension = Application.InputBox(msg)
If (myExtension = "False") + (myExtension = "") Then Exit Sub
Rtn = MsgBox("Include Sub Folders ?", vbYesNo)
SearchSubFolders = Rtn = 6
myList = SearchFiles(myDir, myExtension, 0, temp(), SearchSubFolders)
If Not IsError(myList) Then
Sheets(1).Cells(1).Resize(UBound(myList, 2), 2).Value = _
Application.Transpose(myList)
Else
MsgBox "No file found"
End If
End Sub
Private Function SearchFiles(myDir As String _
, myFileName As String, n As Long, myList() _
, Optional SearchSub As Boolean = False) As Variant
Dim fso As Object, myFolder As Object, myFile As Object
Set fso = CreateObject("Scripting.FileSystemObject")
For Each myFile In fso.getfolder(myDir).Files
Select Case myFile.Attributes
Case 2, 4, 6, 34
Case Else
If (Not myFile.Name Like "~$*") _
* (myFile.Path & "\" & myFile.Name <> ThisWorkbook.FullName) _
* (UCase(myFile.Name) Like UCase(myFileName)) Then
n = n + 1
ReDim Preserve myList(1 To 2, 1 To n)
myList(1, n) = myDir
myList(2, n) = myFile.Name
End If
End Select
Next
If SearchSub Then
For Each myFolder In fso.getfolder(myDir).subfolders
SearchFiles = SearchFiles(myFolder.Path, myFileName, _
n, myList, SearchSub)
Next
End If
SearchFiles = IIf(n > 0, myList, CVErr(xlErrRef))
End Function
Suggest the use of Defined Name Ranges to hold the user maintained list (as show in the picture below)
Let’s add a worksheet for user input of the requirements called “_Tables”.
Then create Defined Name Ranges, for users to enter the requirements, called "_Path", "_Files" and "_SubFldrs"
Then replace all the user’s input in current code
REPLACE THIS
''' With Application.FileDialog(msoFileDialogFolderPicker)
''' If .Show Then
''' myDir = .SelectedItems(1)
''' End If
''' End With
''' msg = "Enter File name and Extension" & vbLf & "following wild" & _
''' " cards can be used" & vbLf & "* # ?"
''' myExtension = Application.InputBox(msg)
''' If (myExtension = "False") + (myExtension = "") Then Exit Sub
''' Rtn = MsgBox("Include Sub Folders ?", vbYesNo)
''' SearchSubFolders = Rtn = 6
with this in order to read the requirements from the worksheet "_Tables"
Set WshLst = ThisWorkbook.Sheets("_Tables")
sPath = WshLst.Range("_Path").Value2
aFleKey = WshLst.Range("_Files").Value2
bSbFldr = UCase(WshLst.Range("_SubFldrs").Value2) = UCase("YES")
aFleKey = WorksheetFunction.Transpose(aFleKey)
then Process the lists
See below the entire code below. It's necessary to have the statement Option Base 1 at the top of the module
Option Explicit
Option Base 1
Sub Fle_FileSearch_List()
Dim WshLst As Worksheet
Dim sPath As String
Dim aFleKey As Variant, vFleKey As Variant
Dim bSbFldr As Boolean
Dim vFleLst() As Variant
Dim lN As Long
Set WshLst = ThisWorkbook.Sheets("_Tables")
sPath = WshLst.Range("_Path").Value2
aFleKey = WshLst.Range("_Files").Value2
bSbFldr = UCase(WshLst.Range("_SubFldrs").Value2) = UCase("YES")
aFleKey = WorksheetFunction.Transpose(aFleKey)
Rem To clear output location
ThisWorkbook.Sheets(1).Columns(1).Resize(, 2).Clear
Rem Process input list
For Each vFleKey In aFleKey
If (vFleKey <> "False") * (vFleKey <> "") Then
Call Fle_FileSearch_Fldrs(sPath, CStr(vFleKey), lN, vFleLst, bSbFldr)
End If: Next
Rem Validate Results & List Files found
If lN > 1 Then
ThisWorkbook.Sheets(1).Cells(1).Resize(UBound(vFleLst, 2), 2) _
.Value = Application.Transpose(vFleLst)
Else
MsgBox "No file found"
End If
End Sub
Also some adjustments to the function (now a procedure) to allow the process of the list.
Sub Fle_FileSearch_Fldrs(sPath As String, _
sFleKey As String, lN As Long, vFleLst() As Variant, _
Optional bSbFldr As Boolean = False)
Dim oFso As Object, oFolder As Object, oFile As Object
Set oFso = CreateObject("Scripting.FileSystemObject")
If lN = 0 Then
lN = 1 + lN
ReDim Preserve vFleLst(1 To 2, 1 To lN)
vFleLst(1, lN) = "Files Found - Path"
vFleLst(2, lN) = "Files Found - Name"
End If
For Each oFile In oFso.GetFolder(sPath).Files
Select Case oFile.Attributes
Case 2, 4, 6, 34
Case Else
If (Not oFile.Name Like "~$*") * _
(oFile.Path & "\" & oFile.Name <> ThisWorkbook.FullName) * _
(UCase(oFile.Name) Like UCase(sFleKey)) Then
lN = lN + 1
ReDim Preserve vFleLst(1 To 2, 1 To lN)
vFleLst(1, lN) = sPath
vFleLst(2, lN) = oFile.Name
End If: End Select: Next
If bSbFldr Then
For Each oFolder In oFso.GetFolder(sPath).subfolders
Call Fle_FileSearch_Fldrs(oFolder.Path, sFleKey, lN, vFleLst, bSbFldr)
Next: End If
End Sub

Loop through folder using array to find lastest version (count) with VBA?

I have attached a code, however, this will only find the files that is present in the folder.
What I want to have is an incremental counter for the files. Thing is that sometimes the version will start something else than 0 or 1, e.g. 3.
Amesto non AN suppliers TEST W20-3 AN then I want the next string to be 4.
I am currently using this, but it will only work if 1 is the first, etc.
I am really stuck.
' Version check
Do While Len(Dir(strPath2 & "Amesto non AN suppliers TEST W" & week & "-" & version & "*.cif")) <> 0
version = version + 1
strPath = getDirectoryPath & "Amesto non AN suppliers TEST W" & week & "-" & version & " " & UserName & ".cif"
Loop
Sub loadversion()
Dim MyFile As String
Dim Counter As Long
'Create a dynamic array variable, and then declare its initial size
Dim DirectoryListArray() As String
ReDim DirectoryListArray(1000)
'Loop through all the files in the directory by using Dir$ function
MyFile = Dir$("C:\Users\niclas.madsen\Desktop\AP\WAVE3\CIF\*.*")
Do While MyFile <> ""
DirectoryListArray(Counter) = MyFile
MyFile = Dir$
Counter = Counter + 1
Loop
' do something here?!
If MyFile = vbNullString Then
Else
End If
'Reset the size of the array without losing its values by using Redim Preserve
ReDim Preserve DirectoryListArray(Counter - 1)
For Counter = 0 To UBound(DirectoryListArray)
'Debug.Print writes the results to the Immediate window (press Ctrl + G to view it)'
Debug.Print DirectoryListArray(Counter)
Next Counter
End Sub
To get the highest version on a filename in your directory, insert the following functions:
Function CheckHighestVersion(path As String, cutLettersAtWordBeginning As Integer) As Integer
Dim file As Variant
Dim toBeCut As String
Dim verLength As Integer
Dim highestVersion As Integer
highestVersion = 0
file = Dir(path)
While (file <> "")
toBeCut = file
toBeCut = Mid(toBeCut, cutLettersAtWordBeginning + 1)
verLength = FindVerLength(toBeCut)
If verLength = -1 Then
CheckHighestVersion = 0
Exit Function
End If
toBeCut = Left(toBeCut, verLength)
If Val(toBeCut) > highestVersion Then
highestVersion = Val(toBeCut)
End If
file = Dir
Wend
CheckHighestVersion = highestVersion
End Function
Function FindVerLength(fileName As String) As Integer
Dim i As Integer
For i = 1 To Len(fileName)
If Not IsNumeric(Mid(fileName, i, 1)) Then
If i = 1 Then
MsgBox "Couldn't obtain the highest version of the files: " & _
"The first letter of the version is not numeric. The letter is " & Mid(fileName, i, 1) & _
". Please use correct amount of letters to be cut at the beginning of the file name."
FindVerLength = -1
Exit Function
End If
FindVerLength = i - 1
Exit Function
End If
Next i
FindVerLength = i
End Function
Call CheckHighestVersion in your Sub. the path is only the directory (e.g. C:\Test\ ), the second parameter is the number of letters you don't need at the beginning of the word. If I counted correctly, that value should be 30+(length of week, week 25 would be 2, week 7 would be 1) in your case. The function returns the highest version contained in that folder.

Resources