Saving VBA Dictionary object in Excel - vba

As part of an Excel Workbook Template a Dictionary object (from the Scripting Runtime Library) is created and added to. Is it possible to save this in some way along with the Workbook such that it is available on starting up the Workbook, or should I just export the data to a worksheet and save it, then reload it in the next time?

I reckon a worksheet is the best bet. You might like to use the very hidden option, which means the sheet can only be made visible by code.
For example:
Worksheets("System").Visible = xlVeryHidden

Why not save it to a file?
Sub Save_Dict(aDict As Scripting.Dictionary, FileitAs As String, Data_ID As String)
Dim one, SaveStr() As String, s As Long
ReDim SaveStr(aDict.Count)
SaveStr(0) = Data_ID
s = 0
For Each one In aDict
s = s + 1
SaveStr(s) = one & vbBack & aDict(one)
Next one
Write Join(SaveStr, vbCrLf)) to FileitAs 'Method of choice
End Sub
'~~~~~~~~~~~~~~~~
sub Get_Dict(aDict as Scripting.Dictionary, FiledAs as String, Data_ID as String) as Long
Dim one, SavedString, nLng as long, i as integer
Read SavedString from FiledAs - 'Method of choice
SavedString = split(SavedString, vbCrLf)
If Ubound(SavedString) =>0 then
Data_ID = SavedString(0)
For nLng = 1 to ubound(SavedString)
i = instr(SavedString(nLng),vbBack)
adict.add left(SavedString(nLng),i-1, Mid(SavedString(nLng),i+1)
next Nlng
End If
End Sub

Related

OpenOffice Calc Merged Cell properties

I've been searching the web for hours and I can't find an answer for this. I can identify that a given cell is merged but I need to know how many rows are included in the merged cell.
Function aac_MergeRowCount(intStartCol as Integer, intStartRow as Integer)
oSheet = ThisComponent.CurrentController.ActiveSheet
oCell = oSheet.GetCellByPosition(intStartCol, intStartRow)
strData = oCell.GetString()
If oCell.IsMerged Then
strCopy = strData
strWasMerged = True
iCount = oCell.GetNumberOfRows()
End If
aac_MergeRowCount = iCount
End Function
Turns out I just needed to ditch OpenOffice and use Excel. The command I was needing is:
strData = oSheet.Cells(r, c).MergeArea.Rows.Count
Which did not work in OpenOffice

VBA: How do I get unique values in a column and insert it into an array?

I have seen multiple codes regarding this topic but I can't seem to understand it.
For instance, if I have a column that records people names, I want to record all unique names into the array.
So if I have a column of names
David
Johnathan
Peter
Peter
Peter
Louis
David
I want to utilize VBA to extract unique names out of the column and place it into an array so when I call the array it would return these results
Array[0] = David
Array[1] = Johnathan
Array[2] = Peter
Array[3] = Louis
Despite a Collection being mentioned and being a possible solution, it is far more efficient to use a Dictionary as it has an Exists method. Then it's just a matter of adding the names to the dictionary if they don't already exist, and then extracting the keys to an array when you're done.
Note that I've made the name comparisons case-sensitive, but you can change that if necessary, to case-insensitive.
Option Explicit
Sub test()
'Extract all of the names into an array
Dim values As Variant
values = Sheet1.Range("Names").Value2 'Value2 is faster than Value
'Add a reference to Microsoft Scripting Runtime
Dim dic As Scripting.Dictionary
Set dic = New Scripting.Dictionary
'Set the comparison mode to case-sensitive
dic.CompareMode = BinaryCompare
Dim valCounter As Long
For valCounter = LBound(values) To UBound(values)
'Check if the name is already in the dictionary
If Not dic.Exists(values(valCounter, 1)) Then
'Add the new name as a key, along with a dummy value of 0
dic.Add values(valCounter, 1), 0
End If
Next valCounter
'Extract the dictionary's keys as a 1D array
Dim result As Variant
result = dic.Keys
End Sub
use Dictionary object and build a Function that returns your array
Function GetUniqeNames(myRng As Range) As Variant
Dim cell As Range
With CreateObject("Scripting.Dictionary") ' instantiate and reference a Dictionary object
For Each cell In myRng ' loop through passed range
.Item(cell.Value2) = 1 ' store current cell name into referenced dictionary keys (duplicates will be overwritten)
Next
GetUniqeNames = .keys ' write referenced dictionary keys into an array
End With
End Function
that you can exploit in your main code as follows
Sub main()
Dim myArray As Variant
With Worksheets("mysheet") ' change "mysheet" to your actual sheet name
myArray = GetUniqeNames(.Range("A1", .Cells(.Rows.Count, 1).End(xlUp))) ' this will take the referenced sheet column A range from row 1 down to last not empty one
End With
End Sub
Is this a VBA question or a question about programming logic? Use a loop on the column with the data. Check each name against the list of existing data items. If it exists in the list, move on the the next name. If it does not exist in the list, add it.
The "list" is a concept, not a concrete tool. It can be a VBA dictionary, if you are comfortable using that. Or it can be a VBA array, which may not perform as fast as a dictionary, but may be more familiar.
Then again, if you add the data to the Excel Data Model, you can use the Distinct aggregation of a pivot table to list out the unique values.
Without more background it's hard to tell if VBA or Data Model is your best approach. Many VBA solutions get created because people are not aware of Excel's capabilities.
You could use Excel functionality like that.
Sub UniqueNames()
Dim vDat As Variant
Dim rg As Range
Dim i As Long
Set rg = Range("A1:A7")
rg.RemoveDuplicates Columns:=Array(1), Header:=xlNo
With ActiveSheet
vDat = WorksheetFunction.Transpose(.Range("A1:" & .Range("A1").End(xlDown).Address))
End With
For i = LBound(vDat) To UBound(vDat)
Debug.Print vDat(i)
Next i
End Sub
Code is based on your example data, i.e. I put your data into column 1. But the code will also alter the table. If you do not want that you have to use other solutions or put the data beforehand in a temporary sheet.
If you dont want to use "Scripting.Dictionary" and your excel does not have Worksheet.unique(...) like mine
Public Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
If UBound(arr) >= 0 Then
IsInArray = Not IsError(Application.Match(stringToBeFound, arr, 0))
Else
IsInArray = False
End If
End Function
Public Function GetUniqueValuesFromColumn(ws As Worksheet, sourceColNum As Long, Optional firstRow As Long = 2) As Variant
Dim val As String
Dim i As Long
Dim arr() As Variant
arr = Array()
For i = firstRow To ws.Cells(Rows.Count, sourceColNum).End(xlUp).Row
val = ws.Cells(i, sourceColNum)
If Not IsInArray(val, arr) Then
ReDim Preserve arr(UBound(arr) + 1)
arr(UBound(arr)) = val
End If
Next i
GetUniqueValuesFromColumn = arr
End Function
Then call it like GetUniqueValuesFromColumn(ThisWorkbook.Worksheets("SomeList"), 1)

Export Excel data to fixed-width text file - field locations

Let me begin by saying I'm kind of new to working with delimited files. I am trying to emulate how a piece of software lays out a text file using Excel.
Here is the code I'm using to create a text file from the worksheet:
Sub Export_Selection_As_Fixed_Length_File()
' Dimension all variables.
Dim DestinationFile, CellValue, Filler_Char_To_Replace_Blanks As String
Dim FileNum, ColumnCount, RowCount, FieldWidth As Integer
Dim sht As Worksheet
'Below are options incase you want to change the folder where VBA stores the .txt file
'We use ActiveWorkbook.Path in this example
'ActiveWorkbook.Path 'the activeworkbook
'ThisWorkbook.Path 'the workbook with the code
'CurDir 'the current directory (when you hit File|open)
'If a cell is blank, what character should be used instead
Filler_Char_To_Replace_Blanks = " "
'Check if the user has made any selection at all
If Selection.Cells.Count < 2 Then
MsgBox "Nothing selected to export"
Selection.Activate
End
End If
'This is the destination file name.
DestinationFile = ActiveWorkbook.Path & "/textfile.txt"
'Obtain next free file handle number.
FileNum = FreeFile()
' Turn error checking off.
On Error Resume Next
' Attempt to open destination file for output.
Open DestinationFile For Output As #FileNum
' If an error occurs report it and end.
If Err <> 0 Then
MsgBox "Cannot open filename " & DestinationFile
Selection.Activate
End
End If
' Turn error checking on.
On Error GoTo 0
' Loop for each row in selection.
For RowCount = 1 To Selection.Rows.Count
For ColumnCount = 1 To Selection.Columns.Count
CellValue = Selection.Cells(RowCount, ColumnCount).Text
If (IsNull(CellValue) Or CellValue = "") Then CellValue = Filler_Char_To_Replace_Blanks
FieldWidth = Cells(1, ColumnCount).Value
If (ColumnCount = Selection.Columns.Count) Then
Print #FileNum, Format$(CellValue, "!" & String(FieldWidth, "#")) & vbCrLf;
Else: Print #FileNum, Format$(CellValue, "!" & String(FieldWidth, "#"));
End If
Next ColumnCount
' Start next iteration of RowCount loop.
Next RowCount
' Close destination file.
Close #FileNum
Selection.Activate
Workbooks.OpenText Filename:=DestinationFile
End Sub
The software I'm trying to emulate has "data locations" and "field sizes." For example, one field has a data location of 77, which means it will start as the 77th character on the line in the text file. (I don't know how common this is, so if it's very common, please excuse the useless information.) And the field size is 12.
If that doesn't make sense, here's a screenshot of a text file. The first line shows what my VBA creates, and the second line is how I want it to look. How can I force the values on the worksheet to start at a certain position on the line based on the column it's in?
It looks like your first row in the selection contains the field's width FieldWidth = Cells(1, ColumnCount).Value. In your problem description you mentioned data locations and field sizes. You need to have this information some where. You could put it on another sheet in the file, which would let you adjust the output of text file, or you could put those values in your VBA code as constants, or your could create a Class. Using something like this will enable you can redefine the fields as needed. The example below uses a simple class and a few private functions in the module
In the example below you'll need to add a sheet named "FieldControl" and place the appropriate values in columns..See the GetFieldControl function. To test the code I used the following:
You'll need to add the following reference to your macro work book. In the VBA editor under the Tools menu select References, then when the dialog box appears select Microsoft Scripting Runtime. (Tools->References)
And with all things code related, there are improvements that could be made to this.
Good Luck with your efforts
The Class (Insert->Class) change the default name to clField (you can call it whatever you like but make sure to update the dim statement GetFieldControl function to match the name you gave it.)
Option Explicit
Public Enum eFieldType
Number
Text
End Enum
Public Name As String
Public Size As Long
Public StartPos As Long
Public Value As String
Public FieldType As eFieldType
The module with a few updates
Option Explicit
Option Base 1 'This makes any defined array start a 1 rather than 0
Sub Export_Selection_As_Fixed_Length_File()
' Dimension all variables.
Dim DestinationFile, CellValue, Filler_Char_To_Replace_Blanks As String
Dim FileNum, ColumnCount, RowCount, FieldWidth As Integer
Dim sht As Worksheet
Dim outputRecord() As String
'Below are options in case you want to change the folder where VBA stores the .txt file
'We use ActiveWorkbook.Path in this example
'ActiveWorkbook.Path 'the activeworkbook
'ThisWorkbook.Path 'the workbook with the code
'CurDir 'the current directory (when you hit File|open)
'If a cell is blank, what character should be used instead
Filler_Char_To_Replace_Blanks = "+"
'Check if the user has made any selection at all
If Selection.Cells.Count < 2 Then
MsgBox "Nothing selected to export"
Selection.Activate
End
End If
'This is the destination file name.
DestinationFile = ActiveWorkbook.Path & "\textfile.txt" 'This was changed to the DOS version of directory separator
On Error GoTo catchFileOpenError 'Poor man's version of Try/Catch
'Get a FileSystemObject using the MSFT Scripting Runtime reference
Dim fd As Scripting.FileSystemObject
Set fd = New Scripting.FileSystemObject
Dim outputFile As Object
Set outputFile = fd.CreateTextFile(DestinationFile, True, False)
' Turn error checking on.
On Error GoTo 0
Dim record As Scripting.Dictionary
'Call a private function that gets the filed control information from the
'Sheet titled FieldControl and the associated range
Set record = GetFieldControl(ActiveWorkbook.Sheets("FieldControl").Range("A2:D7"))
'Declare enumerators to loop through the selection
Dim dataRow As Range
Dim dataFld As Range
'Declare the output buffer, 80 characters
Dim outputBuffer(80) As Byte
'loop thru the selection row by row
For Each dataRow In Selection.Rows
'Initialize buffer to empty value defined by the second parameter
Call InitOutputBuffer(outputBuffer, Filler_Char_To_Replace_Blanks)
'Loop thru each field in the row
For Each dataFld In dataRow.Columns
'Copy the input value into the output byte array
Call CopyStringToByteArray(outputBuffer, StrConv(Trim(CStr(dataFld.Value2)), vbFromUnicode), _
record(dataFld.Column).StartPos, record(dataFld.Column).FieldType, record(dataFld.Column).Size)
Next dataFld
'Write the record to the text file but first convert ASCII Byte to Unicode String
'Also this method places CR/LF as part of the output to the file
outputFile.WriteLine StrConv(outputBuffer, vbUnicode)
Next dataRow
' Close destination file.
outputFile.Close
Selection.Activate
Workbooks.OpenText Filename:=DestinationFile
Exit Sub
catchFileOpenError: 'Catch the error after trying if openning the file fails
On Error GoTo 0
MsgBox "Cannot open filename " & DestinationFile
Selection.Activate
End Sub
'***********************************************************************************
'*
'* PARAMETERS:
'* outBuf is the updated buffer
'* inBuf is the input buffer that needs to be copied to the output buffer (buffer)
'* startCol is the starting column for the field
'* fldTy is the field type as defined by the class enumerator eFieldType
'* fldLen is the length of the field as defined on the control sheet
Private Sub CopyStringToByteArray(ByRef outBuf() As Byte, ByRef inBuf() As Byte, _
ByVal startCol As Long, ByRef fldTy As eFieldType, ByVal fldLen As Long)
Dim idx As Long
If fldTy = Text Then 'Left Justified
For idx = LBound(inBuf) To UBound(inBuf)
outBuf(startCol) = inBuf(idx)
startCol = startCol + 1
Next idx
Else 'Right Justified
Dim revIdx As Long
revIdx = startCol + fldLen - 1
For idx = UBound(inBuf) To LBound(inBuf) Step -1
outBuf(revIdx) = inBuf(idx)
revIdx = revIdx - 1
Next idx
End If
End Sub
'***************************************************************************
'* InitOutputBuffer
'* PARAMETERS:
'* buffer is the buffer to initialize
'* initVal is a string containing the value used to initialize the buffer
Private Sub InitOutputBuffer(ByRef buffer() As Byte, ByVal initVal As String)
Dim byInitVal() As Byte 'Byte array to hold the values from the string conversion
byInitVal = StrConv(initVal, vbFromUnicode) 'convert the string into an ASCII array
Dim idx As Long
For idx = LBound(buffer) To UBound(buffer)
buffer(idx) = byInitVal(0)
Next idx
'buffer(81) = Asc(Chr(13)) 'Carriage Return Character
'buffer(82) = Asc(Chr(10)) 'Line Feed Character
End Sub
'*******************************************************************************
'*
'* GetFieldControl
'* PARAMETERS:
'* ctrlRng is the range on a worksheet where the field control info is
'* found
'* REMARKS:
'* The range needs to have the following columns: Name, Size, Start Postion
'* and Type. Type values can be Text or Number
Private Function GetFieldControl(ByRef ctrlRng As Range) As Scripting.Dictionary
Dim retVal As Scripting.Dictionary
Set retVal = New Scripting.Dictionary
'format of control range is : Name, Size, Start Position, Type
Dim fldInfoRow As Range
Dim fld As clField 'A class that holds the control values from the work sheet
Dim colCnt As Long: colCnt = 1 'Becomes the key for the dictionary
For Each fldInfoRow In ctrlRng.Rows
Set fld = New clField
fld.Name = fldInfoRow.Value2(1, 1) 'Name of field in data table
fld.Size = fldInfoRow.Value2(1, 2) 'Output Size of field
fld.StartPos = fldInfoRow.Value2(1, 3) 'Output starting position for this field
Select Case fldInfoRow.Value2(1, 4) 'Controls how the output value is formated
Case "Text" ' Text left justified, Numbers are right justified
fld.FieldType = Text
Case "Number"
fld.FieldType = Number
Case Default
fld.FieldType = Text
End Select
retVal.Add Key:=colCnt, Item:=fld 'Add the key and the fld object to the dictionary
colCnt = colCnt + 1 'This key value is mapped to the column number in the input data table
Next fldInfoRow
'Return the scripting Dictionary
Set GetFieldControl = retVal
End Function

Access variables and their names from the current scope

Is it possible to:
Access a list of all variables in a VBA runtime environment?
Access the name of a variable with VBA?
Example:
function v2S(str as string) as string
For each variable in Variables
dim I as integer
for I = 1 to 10
v2S = replace(v2S,"%" & variable.name & "%", variable.value)
next
next
end function
Example use case:
Dim skyColor as string
skyColor = "green"
Debug.Print v2S("The sky is %skyColor% today!")
There is an application I can send commands to via a com object and I wish to do something along the lines of:
Dim i a integer
for i = 1 to MI.Eval("numtables()")
MI = GetObject(,"MapInfo.Application.x64")
debug.print MI.Eval(v2S("tableinfo(%i%,1)")) ' Print name of table
next
The above looks much cleaner than:
Dim i a integer
for i = 1 to MI.Eval("numtables()")
MI = GetObject(,"MapInfo.Application.x64")
debug.print MI.Eval(v2S("tableinfo(" & i & ",1)")) ' Print name of table
next
But of course if it were possible I would want it to be general which may be difficult...
For my own use case this is pretty good.
However it still isn't very readable. This is another option. It's more readable but also more cluttered:
Sub Main()
Dim Vars as object, myString as string
set Vars = CreateObject("scripting.Dictionary")
Vars.add "Var1","Val1"
Vars.add "Var2","Val2"
'...
myString = r("Var1: #{Var1} and Var2: #{Var2}", Vars)
End Sub
function r(byval s as string, byval o as object) as string
for each key in o.keys
s = replace(s,"#{" & key & "}",o.item(key))
next
r = s
end function
I wish string interpolation functionality existed by default in VBA.

vba that searches for a string in all the files inside a folder and its subfolders

I have a huge script to make which I had partly completed (parsing xml file to vba and deleting certain unwanted childs),but i am struck at one point.
I have strings (that are obtained from my previous output) in cells A1:A1500 in my worksheet and I have a folder named "model" in the same path where my workbook is placed (the folder has many subfolders and inside subfolders many .c , .h , .xml file types are present).
I need a script that will take the string in A1 and search inside all the files in the folder "model" and its subfolders and if the string is present in any of the files I have to print/put "string found" in cell B1 and if the string is not present in any of the files I have to print/put "Not found" in cell B1. In the same way I need to search all the strings from A2:A1500 inside all the files in the folder "model" and print/put "string found"/not found in the cells B2:B1500.
Below are some of the strings I have in my worksheet in column A1:A4:
vel_gradient
D_speed_20
AGB_router_1
F10_35_XS
I am somewhat familiar with vba but I am not sure how to implement this.
Any help regarding the script is accepted. Can someone help me with this.
As noted in the question comments, the answer to this question involves recursion, which means that one or more sub routines or functions call themselves again and again and again, etc. Fortunately, Excel will keep track of all of this for you. My solution also takes advantage of an Excel trick that allows you to create or unload arrays without iterating by using the Range.Value property. Also included is a string indent variable to help visualize how the recursion is happening. Just comment out the Debug.Print statements when no longer needed.
The solution involves 3 steps.
Create an array of all of the strings which could be matched along with 2 parallel arrays to hold the found / not found strings and the first file where the string was matched
Pass the 3 arrays ByRef to a sub routine that processes all of the sub folders and files for a given folder. Any sub folders recurse back into the folder sub routine, while files are processed by a separate file routine.
After all sub folders and files have been processed, the found / not found column is populated from the associated array.
Enjoy
Step 1 - The main method
' The main sub routine.
Public Sub FindStrings(strFolder As String, Optional wksSheet As Worksheet = Nothing)
' Used examples given, better to convert to variables and calculate at run time.
Const lngFirstRow As Long = 1
Const lngLasstRow As Long = 1500
Const strStringsCol As String = "A"
Const strMatchesFoundCol As String = "B"
Const strFileNamesCol As String = "C"
Dim lngIndex As Long, lngFolderCount As Long, lngFileCount As Long
Dim strIndent As String
Dim varStrings As Variant, varMatchesFound As Variant, varFileNames As Variant
If wksSheet Is Nothing Then
Set wksSheet = ActiveSheet
End If
With wksSheet
' Create the strings array from the given range value.
varStrings = .Range(.Cells(lngFirstRow, strStringsCol), .Cells(lngLasstRow, strStringsCol)).Value
' Transpose the strings array into a one dimentional array.
varStrings = Application.WorksheetFunction.Transpose(varStrings)
End With
' Initialize file names array to empty strings.
ReDim varFileNames(LBound(varStrings) To UBound(varStrings))
For lngIndex = LBound(varFileNames) To UBound(varFileNames)
varFileNames(lngIndex) = vbNullString
Next
' Initialize matches found array to empty strings.
ReDim varMatchesFound(LBound(varStrings) To UBound(varStrings))
For lngIndex = LBound(varMatchesFound) To UBound(varMatchesFound)
varMatchesFound(lngIndex) = vbNullString
Next
' Process the main folder.
Call ProcessFolder(strFolder, strIndent, varStrings, varMatchesFound, varFileNames, lngFolderCount, lngFileCount)
' Finish setting up matches found array.
For lngIndex = LBound(varMatchesFound) To UBound(varMatchesFound)
If Len(Trim$(varMatchesFound(lngIndex))) = 0 Then
varMatchesFound(lngIndex) = "Not found"
End If
Next
' Transpose the associated arrays so we can use them to load found / not found and file names columns.
varFileNames = Application.WorksheetFunction.Transpose(varFileNames)
varMatchesFound = Application.WorksheetFunction.Transpose(varMatchesFound)
' Set up the found / not found column data from the matches found array.
With wksSheet
.Range(.Cells(lngFirstRow, strFileNamesCol), .Cells(lngLasstRow, strFileNamesCol)).Value = varFileNames
.Range(.Cells(lngFirstRow, strMatchesFoundCol), .Cells(lngLasstRow, strMatchesFoundCol)).Value = varMatchesFound
End With
Debug.Print "Folders: "; lngFolderCount, "Files: "; lngFileCount
End Sub
Step 2 - The process sub folder method
Private Sub ProcessFolder(strFolder As String, ByRef strIndent As String, ByRef varStrings As Variant, ByRef varMatchesFound As Variant, ByRef varFileNames As Variant, ByRef lngFolderCount As Long, lngFileCount As Long)
Dim objFileSystemObject As Object, objFolder As Object, objFile As Object
' Use late binding throughout this method to avoid having to set any references.
Set objFileSystemObject = CreateObject("Scripting.FileSystemObject")
lngFolderCount = lngFolderCount + 1
Debug.Print strIndent & "Dir: " & Format(lngFolderCount, "###,##0 ") & strFolder
For Each objFolder In objFileSystemObject.GetFolder(strFolder).SubFolders
If objFolder.Name = "history" Then
'Do Nothing
Else
' Recurse with the current sub folder.
Call ProcessFolder(objFolder.Path, strIndent & " ", varStrings, varMatchesFound, varFileNames, lngFolderCount, lngFileCount)
End If
Next
' Process any files found in the current folder.
For Each objFile In objFileSystemObject.GetFolder(strFolder).Files
Call ProcessFile(objFile.Path, strIndent & " ", varStrings, varMatchesFound, varFileNames, lngFileCount)
Next
Set objFileSystemObject = Nothing: Set objFolder = Nothing: Set objFile = Nothing
End Sub
Step 3 - The process file method
Private Sub ProcessFile(strFullPath As String, ByRef strIndent As String, ByRef varStrings As Variant, ByRef varMatchesFound As Variant, ByRef varFileNames As Variant, ByRef lngFileCount As Long)
On Error Resume Next
Dim objFileSystemObject As Object
Dim strFileContent As String
Dim lngIndex As Long
lngFileCount = lngFileCount + 1
Debug.Print strIndent & "File: " & Format(lngFileCount, "###,##0 ") & strFullPath
' Use late binding throughout this method to avoid having to set any references.
Set objFileSystemObject = CreateObject("Scripting.FileSystemObject")
strFileContent = objFileSystemObject.OpenTextFile(strFullPath).Readall()
If Err.Number = 0 Then
' Check for matched strings by iterating over the strings array.
For lngIndex = LBound(varStrings) To UBound(varStrings)
' Skip zero length strings.
If Len(Trim$(varStrings(lngIndex))) > 0 Then
' We have a matched string.
If InStr(1, strFileContent, varStrings(lngIndex), vbTextCompare) > 0 Then
' Set up parallel arrays the first time the string is matched.
If Len(Trim$(varMatchesFound(lngIndex))) = 0 Then
' Set corresponding array value.
varMatchesFound(lngIndex) = "String found"
' Save file name where first match was found.
varFileNames(lngIndex) = strFullPath
End If
End If
End If
Next
Else
Err.Clear
End If
Set objFileSystemObject = Nothing
On Error GoTo 0
End Sub
If your files are not too large you can read all the content in one shot:
Sub Tester()
Debug.Print StringInFile("C:\_Stuff\test\File_Val2.txt", "xxx")
End Sub
Function StringInFile(fPath, txtSearch) As Boolean
StringInFile = InStr(CreateObject("scripting.filesystemobject").opentextfile( _
fPath).Readall(), txtSearch) > 0
End Function
However if you need to test for multiple strings it would be more efficient to read the file once and then check for each string using instr()