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
Related
I am trying to work out how to use filesystemobject to include date created, date modified, size, path, file/folder names of files and folders into an excel vba dynamic array so that it automatically expands or contracts to the list of files/folders.
In addition, I am trying to make a list of excluded folder paths so that when I click search, only those folder paths and its files are excluded from the result list, but other folders and its files are shown. Is it possible to make a list of folder paths which will exclude deeper nested folder subfolders?
For example, In this folder C:\test with spaces\ (see image) folder structure I want to exclude the file in C:\test with spaces\subfolder 1\2ndlevelsubfolder1\ including "2ndlevelsubfolder1", but I want all other folders paths to be displayed. How can I do this with vba?
Finally, I also want to make this list recursive, so that every time I add/remove the excluded list of folder paths, new entries will be added right after the previous list. I have these functions made in different excel workbooks but the only problem is incorporating them together into one code. I am showing you my code from 2 workbooks:
This code is for recursive listing:
Option Explicit
Sub SomeSub()
Call GetFiles("\\?\[INSERT PARENT FOLDER PATH HERE]") 'attach "\\?\" at the beginning for long folder path names! ex..'GetFiles("\\?\INSERT..."
'can also list multiple "Call GetFiles("\\?\[insert new folder path here]")" to list multiple folder paths all at once
End Sub
Sub GetFiles(ByVal path As String)
Dim FSO As Object
Set FSO = CreateObject("Scripting.FileSystemObject")
Dim folder As Object
Set folder = FSO.GetFolder(path)
Dim SubFolder As Object
Dim file As Object
For Each SubFolder In folder.Subfolders
GetFiles (SubFolder.path)
Next SubFolder
Range("A1") = "parent folder"
'Range("A1").Offset(0, 1) = "FILE/FOLDER PATH"
Range("A1").Offset(0, 3) = "FILE or FOLDER"
Range("A1").Offset(0, 4) = "DATE CREATED"
Range("A1").Offset(0, 5) = "DATE MODIFIED"
Range("A1").Offset(0, 6) = "SIZE"
Range("A1").Offset(0, 7) = "TYPE"
Range("A" & Rows.Count).End(xlUp).Offset(1, 0) = Replace(folder, "\\?\", "")
'Range("A" & Rows.Count).End(xlUp).Offset(0, 1) = Replace(folder, "\\?\", "")
'Range("A" & Rows.Count).End(xlUp).Offset(0, 2) = folder.Name
Range("A" & Rows.Count).End(xlUp).Offset(0, 3) = "FOLDER"
Range("A" & Rows.Count).End(xlUp).Offset(0, 4) = folder.datecreated
Range("A" & Rows.Count).End(xlUp).Offset(0, 5) = folder.DateLastModified
For Each SubFolder In folder.Subfolders
'Range("A" & Rows.Count).End(xlUp).Offset(1, 0) = Replace(subfolder.path, "\\?\", "")
'Range("A" & Rows.Count).End(xlUp).Offset(0, 1) = Replace(folder, "\\?\", "")
'Range("A" & Rows.Count).End(xlUp).Offset(0, 2) = subfolder.Name
'Range("A" & Rows.Count).End(xlUp).Offset(0, 3) = "FOLDER"
'Range("A" & Rows.Count).End(xlUp).Offset(0, 4) = subfolder.datecreated
'Range("A" & Rows.Count).End(xlUp).Offset(0, 5) = subfolder.DateLastModified
Next SubFolder
For Each file In folder.Files
Range("A" & Rows.Count).End(xlUp).Offset(1, 0) = Replace(file.path, "\\?\", "")
'Range("A" & Rows.Count).End(xlUp).Offset(0, 1) = Replace(folder, "\\?\", "")
'Range("A" & Rows.Count).End(xlUp).Offset(0, 2) = file.Name
Range("A" & Rows.Count).End(xlUp).Offset(0, 3) = "FILE"
Range("A" & Rows.Count).End(xlUp).Offset(0, 4) = file.datecreated
Range("A" & Rows.Count).End(xlUp).Offset(0, 5) = file.DateLastModified
Range("A" & Rows.Count).End(xlUp).Offset(0, 6) = file.Size
Range("A" & Rows.Count).End(xlUp).Offset(0, 7) = file.Type
Next file
With Range("E:F")
.NumberFormat = "dddd mmmm dd, yyyy H:mm:ss AM/PM" 'long file date and time
End With
Set FSO = Nothing
Set folder = Nothing
Set SubFolder = Nothing
Set file = Nothing
End Sub
This is the excluded folder name list code in cell A3 only the names are inserted at cell A3 seperated by commas with no spaces after the comma. I want folder paths at any subfolder level to be excluded, not just names at the 1st level
Option Explicit
'http://www.ozgrid.com/forum/showthread.php?t=158478
Dim iRow As Long
Sub ListFiles()
Dim lRow As Long
iRow = 11
lRow = Range("B" & Rows.Count).End(xlUp).Row
If lRow >= iRow Then
Range("B" & iRow & ":E" & Range("B" & Rows.Count).End(xlUp).Row).Clear
End If
Call ListMyFiles(Range("A1"), Range("A2"), Range("A3")) 'Cell A1 is the parent directory, A2 is include subfolders as false or true _
cell A3 is the exclude folder names within the parent directory _
which only works in the 1st level not deeper nested levels
Application.GoTo Range("B3"), True
End Sub
Sub ListMyFiles(mySourcePath As String, IncludeSubfolders As String, _
Optional excludedSubfolders As String = " ")
Dim myObject As Scripting.FileSystemObject
Dim mySource As Scripting.folder, myFile As Variant
Dim myfolder As Variant
Dim iCol As Integer
Dim mySubFolder As Scripting.folder, v As Variant
Dim asf() As String, sf As String
asf() = Split(Replace(excludedSubfolders, ", ", ","), ",")
Set myObject = New Scripting.FileSystemObject
If Right(mySourcePath, 1) <> "\" Then mySourcePath = mySourcePath + "\"
Set mySource = myObject.GetFolder(mySourcePath)
On Error Resume Next
For Each mySubFolder In mySource.SubFolders
iCol = 1
Cells(iRow, iCol).Value = mySubFolder.Path
iCol = iCol + 1
Cells(iRow, iCol).Value = mySubFolder.Name
iRow = iRow + 1
Next mySubFolder
If IncludeSubfolders Then
For Each mySubFolder In mySource.SubFolders
If excludedSubfolders = " " Then
Call ListMyFiles(mySubFolder.Path, True)
Else
sf = Trim(Right(mySubFolder.Path, Len(mySubFolder.Path) - Len(mySourcePath)))
If IndexStrArray(asf(), sf) = -1 Then Call ListMyFiles(mySubFolder.Path, True)
End If
Next
End If
End Sub
'val is not case sensitive
Function IndexStrArray(vArray() As String, sVal As String) As Long
Dim v As Variant, i As Long
On Error GoTo Minus1
For i = 0 To UBound(vArray)
If LCase(vArray(i)) = LCase(sVal) Then
IndexStrArray = i
Exit Function
End If
Next i
Minus1:
IndexStrArray = -1
End Function
I hope this has shed some light on what I want to achieve. Thank you & hope to hear from you soon.
Not sure it'll 100% match your needs.
You should use collections, and recursive sub, like this (not fully tested, it might needs some corrections):
' List of complete path of files in folder / subfolders
' Needs to add "Microsoft Scripting Runtime" reference to your file
Sub FolderFilesPath(ByVal pFolder As String, ByRef pColFiles As Collection, _
Optional ByVal pGetSubFolders As Boolean, Optional ByVal pFilter As Collection)
Dim sFolder As String
Dim oFSO As New FileSystemObject
Dim oFolder, oSubFolder As Folder
Dim oFile As File
sFolder = IIf(Right(pFolder, 1) <> "\", pFolder & "\", pFolder)
Set oFolder = oFSO.GetFolder(sFolder)
If Not ExistsInCollection(pFilter, oFolder) Then
For Each oFile In oFolder.Files
pColFiles.Add oFile
Next oFile
If pGetSubFolders Then
For Each oSubFolder In oFolder.SubFolders
FolderFilesPath oSubFolder.Path, pColFiles, pGetSubFolders,
pFilter
Next
End If
End If
End Sub
' Vba collection contains
Function ExistsInCollection(col As Collection, key As Variant) As Boolean
On Error GoTo err
ExistsInCollection = True
IsObject (col.Item(key))
Exit Function
err:
ExistsInCollection = False
End Function
'------------------------------------------------------------------------------
Sub TestMe()
Dim colFiles As New Collection, sFilePath As Variant
Dim colExcludedFolders As New Collection
With colExcludedFolders
.Add "C:\test with spaces\subfolder 1\"
End With
FolderFilesPath ThisWorkbook.Path, colFiles, True, colExcludedFolders
' colFiles contains filtered files
For Each sFilePath In colFiles
With sFilePath
Debug.Print .Path & " - " & .Name & " - " & .DateCreated
End With
Next sFilePath
End Sub
Now i am getting Run-time error '28': Out of stack space
What is wrong with this code?
I am trying to design a macro to search for multiple strings in an excel.
I have the following code which searches for the word "techno" in an excel but, I need to include a variable into the code so that I can search for multiple words such "Techno", "electromagnetic", "waves", etc. at once. I am unable to create a loop for this condition.
Can anyone suggest a solution to this problem? The below code works fine but, only a tweak is required to include multiple strings in the search.
Sub SearchFolders()
Dim xFso As Object
Dim xFld As Object
Dim xStrSearch As String
Dim xStrPath As String
Dim xStrFile As String
Dim xOut As Worksheet
Dim xWb As Workbook
Dim xWk As Worksheet
Dim xRow As Long
Dim xFound As Range
Dim xStrAddress As String
Dim xFileDialog As FileDialog
Dim xUpdate As Boolean
Dim xCount As Long
myArray = Array("techno", "magnetic", "laser", "trent")
On Error GoTo ErrHandler
Set xFileDialog = Application.FileDialog(msoFileDialogFolderPicker)
xFileDialog.AllowMultiSelect = False
xFileDialog.Title = "Select a forlder"
If xFileDialog.Show = -1 Then
xStrPath = xFileDialog.SelectedItems(1)
End If
If xStrPath = "" Then Exit Sub
xUpdate = Application.ScreenUpdating
Application.ScreenUpdating = False
Set xOut = Worksheets.Add
For myCounter = 0 To UBound(myArray)
MsgBox myCounter & " is the Count No."
xStrSearch = myArray(myCounter)
MsgBox xStrSearch & " is the Value fr String search"
xRow = 1
With xOut
.Cells(xRow, 1) = "Workbook"
.Cells(xRow, 2) = "Worksheet"
.Cells(xRow, 3) = "Cell"
.Cells(xRow, 4) = "Text in Cell"
Set xFso = CreateObject("Scripting.FileSystemObject")
Set xFld = xFso.GetFolder(xStrPath)
xStrFile = Dir(xStrPath & "*.xls*")
Do While xStrFile <> ""
Set xWb = Workbooks.Open(Filename:=xStrPath & "\" & xStrFile, UpdateLinks:=0, ReadOnly:=True, AddToMRU:=False)
For Each xWk In xWb.Worksheets
Set xFound = xWk.UsedRange.Find(xStrSearch)
MsgBox xFound & " is the strings found"
If Not xFound Is Nothing Then
xStrAddress = xFound.Address
End If
Do
If xFound Is Nothing Then
Exit Do
Else
xCount = xCount + 1
MsgBox xCount & " is the count of strings"
xRow = xRow + 1
.Cells(xRow, 1) = xWb.Name
.Cells(xRow, 2) = xWk.Name
.Cells(xRow, 3) = xFound.Address
.Cells(xRow, 4) = xFound.Value
End If
Set xFound = xWk.Cells.FindNext(After:=xFound)
MsgBox xFound & " next string"
MsgBox xStrAddress & " is the address "
MsgBox xFound.Address & " is the address found"
Loop While xStrAddress <> xFound.Address 'To check how xStrAddress is populated or do we need to declare it as a help from excel pointed out
myCounter = myCounter + 1
Next
xWb.Close (False)
xStrFile = Dir
Loop
.Columns("A:D").EntireColumn.AutoFit
End With
Next myCounter
MsgBox xCount & "cells have been found", ,
ExitHandler:
Set xOut = Nothing
Set xWk = Nothing
Set xWb = Nothing
Set xFld = Nothing
Set xFso = Nothing
Application.ScreenUpdating = xUpdate
Exit Sub
ErrHandler:
MsgBox Err.Description, vbExclamation
Resume ExitHandler
End Sub
If the strings you are searching will always be the same, hard code them into an array and Loop through the array elements to search each string, like so:
Dim myArray as Variant
Dim myCounter as Long
myArray = Array("techno", "electromagnetic", ...etc.)
For myCounter = 0 To UBound(myArray)
... 'your code here
xStrSearch = myArray(myCounter)
... 'the rest if your code here
Next myCounter
I have a 20x3 table on an excel sheet. Each of the three columns is labeled Date, Price, and Volume. I want to convert this data into a .txt file that contains an array of array, i.e an array containing twenty arrays, where each of the twenty arrays has the format [Date, price, volume]. The final array should have the format:
[[Date_0, Price_0, Volume_0], . . .,[Date_19, Price_19, Volume_19]].
I believe this can be done by writing a loop for each row and printing as an array.
This is a modification from the above that will take input as a range. It is capable of handling ranges with several areas (multiselection).
Public Sub writeRangeToFile(ByRef rng As Range, ByVal path As String)
Dim fso As Object, _
fOut As Object, _
rArea As Range, _
row As Integer, _
col As Integer
Set fso = CreateObject("Scripting.FileSystemObject")
Set fOut = fso.CreateTextFile(path, overwrite:=True, Unicode:=False)
With fOut
For Each rArea In rng.Areas '' iterate over areas of range, insures all are rects
fOut.Write "["
For row = 1 To rArea.Rows.Count Step 1
.Write IIf(row > 1, ",", "") & "["
For col = 1 To rArea.Columns.Count Step 1
.Write IIf(col > 1, ",", "") & rArea.Cells(row, col).Value
Next col
.Write "]"
Next row
.Write "]" & vbCrLf
Next rArea
.Close
End With
End Sub
Tester
This serves as a general test case, but I think you would want to use a named range in place of Selection in your case
Sub tester()
writeRangeToFile Selection, "C:\[your directory]\Test.txt"
End Sub
Output
Given the selection of
the tester function outputs
[[B2,C2,D2,E2,F2,G2],[B3,C3,D3,E3,F3,G3],[B4,C4,D4,E4,F4,G4],[B5,C5,D5,E5,F5,G5]]
[[M3,N3,O3,P3,Q3],[M4,N4,O4,P4,Q4],[M5,N5,O5,P5,Q5],[M6,N6,O6,P6,Q6],[M7,N7,O7,P7,Q7],[M8,N8,O8,P8,Q8]]
[[D10,E10,F10,G10,H10,I10,J10],[D11,E11,F11,G11,H11,I11,J11],[D12,E12,F12,G12,H12,I12,J12],[D13,E13,F13,G13,H13,I13,J13],[D14,E14,F14,G14,H14,I14,J14],[D15,E15,F15,G15,H15,I15,J15],[D16,E16,F16,G16,H16,I16,J16]]
[[Q15,R15,S15,T15],[Q16,R16,S16,T16],[Q17,R17,S17,T17],[Q18,R18,S18,T18],[Q19,R19,S19,T19],[Q20,R20,S20,T20]]
You can do this using the Open path For Output call, and then by iterating across the array in both directions.
Sub writeArrToFile(ByRef arr() As String, ByVal path As String)
Dim lOuter As Integer, _
uOuter As Integer, _
lInner As Integer, _
uInner As Integer
Open path For Output As #1
Let lOuter = LBound(arr(), 1)
Let uOuter = UBound(arr(), 1)
Let lInner = LBound(arr(), 2)
Let uInner = UBound(arr(), 2)
Print #1, "[";
For i = lOuter To uOuter
Print #1, IIf(i > lOuter, ",", ""); "[";
For j = lInner To uInner
Print #1, IIf(j > lInner, ",", ""); arr(i, j);
Next j
Print #1, "]";
Next i
Print #1, "]";
Close #1
End Sub
or you may achieve this by using a more modern, object oriented approach with
Sub writeArrToFile(ByRef arr() As String, ByVal path As String)
Dim fso As Object, _
fOut As Object, _
lInner As Integer, _
lOuter As Integer
Set fso = CreateObject("Scripting.FileSystemObject")
Set fOut = fso.CreateTextFile(path, overwrite:=True, Unicode:=False)
Let lInner = LBound(arr(), 2)
Let uInner = UBound(arr(), 2)
With fOut
.Write "["
For i = LBound(arr(), 1) To UBound(arr(), 1) Step 1
.Write IIf(i > lOuter, ",", "") & "["
For j = lInner To uInner
.Write IIf(j > lInner, ",", "") & arr(i, j)
Next j
.Write "]"
Next i
.Write "]"
.Close
End With
End Sub
Tester Function
You can test the above with this function. Modify the file path to designate where the subroutine should output.
Sub tester()
Dim arr(0 To 2, 0 To 2) As String
arr(0, 0) = "a"
arr(0, 1) = "b"
arr(0, 2) = "c"
arr(1, 0) = "d"
arr(1, 1) = "e"
arr(1, 2) = "f"
arr(2, 0) = "g"
arr(2, 1) = "h"
arr(2, 2) = "i"
writeArrToFile arr, "C:\[your directory]\Test.txt"
End Sub
Output
The above tester function outputs to "C:\[your directory]\Test.txt"
[[a,b,c],[d,e,f],[g,h,i]]
I have a database of about 140,000 test files. I am looking to loop through each folder and pull information from the file name of text and excel files so as to organize the data a little better.
I have found ways to pick a folder path and import information about each file using the code below. This works great except I would like to only pull information from excel and text files and I would also like to pull additional text information from the filename as well. For example I might have a file named:
"444555_CAT1010EL_650-700-800C-2hr laging NOT CH4.txt"
And I would want to print:
the 6 numbers at the beginning of the name (they could be anything) in this example "444555" in one column
print the 3 letters (they could be anything) before "1010EL" in another column. In this example "CAT"
"CH4" in the final column OR even have a column for "CH4" and if the filename contains "CH4" put an X in that column
have a column for "laging" and if the filename contains "laging" anywhere put an X in that column
Thank you in advance for your help.
Sub Compile3()
Dim oShell As Object
Dim oFile As Object
Dim oFldr As Object
Dim lRow As Long
Dim iCol As Integer
Dim vArray As Variant
vArray = Array(10, 0, 1, 156, 2, 4, 144, 146, 183, 185)
'0=Name, 31=Dimensions, 1=Size, 163=Vertical Resolution
Set oShell = CreateObject("Shell.Application")
'-------------------ROW INFO INPUT OPTIONS-----------------
'' 1)
' lRow = 1
' 2) find first empty row in database for bottletracker
'
Dim iRow As Long
iRow = Cells.find(What:="*", SearchOrder:=xlRows, SearchDirection:=xlPrevious, LookIn:=xlValues).Row
lRow = iRow
'------------------------------------------------------------
With Application.FileDialog(msoFileDialogFolderPicker)
.title = "Select the Folder..."
If .Show Then
Set oFldr = oShell.Namespace(.SelectedItems(1))
With oFldr
'Column header information
For iCol = LBound(vArray) To UBound(vArray)
Cells(lRow, iCol + 4) = .getdetailsof(.items, vArray(iCol))
Next iCol
For Each oFile In .items
lRow = lRow + 1
For iCol = LBound(vArray) To UBound(vArray)
Cells(lRow, iCol + 4) = .getdetailsof(oFile, vArray(iCol))
Next iCol
Next oFile
End With
End If
End With
End Sub
I'd use this code. There's three separate procedures at the end that find the last cell on the sheet, return the folder and return all files within the folder.
The main code then looks at each file name and pulls the required information from it.
Note, this code: InStr(sFileName, "CAT") <> 0 will return TRUE/FALSE depending if the text "CAT" is within the file name. InStr(sFileName, "CAT") returns the position of "CAT" within the text, and <>0 turns that into a boolean depending on if it's different from 0.
Option Explicit
Public Sub Test()
Dim sFolder As String
Dim cFiles As Collection
Dim vFile As Variant
Dim sFileName As String
Dim rLastCell As Range
sFolder = GetFolder("S:\DB_Development_DBC\") & Application.PathSeparator
Set cFiles = New Collection
EnumerateFiles sFolder, "*.xls*", cFiles
EnumerateFiles sFolder, "*.txt", cFiles
With ThisWorkbook.Worksheets("Sheet1")
For Each vFile In cFiles
Set rLastCell = LastCell(ThisWorkbook.Worksheets("Sheet1")).Offset(1) 'Find last row
sFileName = Mid(vFile, InStrRev(vFile, Application.PathSeparator) + 1) 'Get just file name from path.
.Cells(rLastCell.Row, 1) = Left(sFileName, 6) 'First 6 characters.
.Cells(rLastCell.Row, 2) = Mid(sFileName, InStr(sFileName, "1010EL") - 3, 3) '3 characters before 1010EL.
.Cells(rLastCell.Row, 3) = InStr(sFileName, "CH4") <> 0 'Contains CH4.
.Cells(rLastCell.Row, 4) = InStr(sFileName, "laging") <> 0 'Contains laging.
Next vFile
End With
End Sub
Sub EnumerateFiles(ByVal sDirectory As String, _
ByVal sFileSpec As String, _
ByRef cCollection As Collection)
Dim sTemp As String
sTemp = Dir$(sDirectory & sFileSpec)
Do While Len(sTemp) > 0
cCollection.Add sDirectory & sTemp
sTemp = Dir$
Loop
End Sub
Function GetFolder(Optional startFolder As Variant = -1) As Variant
Dim fldr As FileDialog
Dim vItem As Variant
Set fldr = Application.FileDialog(msoFileDialogFolderPicker)
With fldr
.Title = "Select a Folder"
.AllowMultiSelect = False
If startFolder = -1 Then
.InitialFileName = Application.DefaultFilePath
Else
If Right(startFolder, 1) <> "\" Then
.InitialFileName = startFolder & "\"
Else
.InitialFileName = startFolder
End If
End If
If .Show <> -1 Then GoTo NextCode
vItem = .SelectedItems(1)
End With
NextCode:
GetFolder = vItem
Set fldr = Nothing
End Function
Public Function LastCell(wrkSht As Worksheet, Optional Col As Long = 0) As Range
Dim lLastCol As Long, lLastRow As Long
On Error Resume Next
With wrkSht
If Col = 0 Then
lLastCol = .Cells.Find("*", , , , xlByColumns, xlPrevious).Column
lLastRow = .Cells.Find("*", , , , xlByRows, xlPrevious).Row
Else
lLastCol = .Cells.Find("*", , , , xlByColumns, xlPrevious).Column
lLastRow = .Columns(Col).Find("*", , , , xlByColumns, xlPrevious).Row
End If
If lLastCol = 0 Then lLastCol = 1
If lLastRow = 0 Then lLastRow = 1
Set LastCell = wrkSht.Cells(lLastRow, lLastCol)
End With
On Error GoTo 0
End Function
Edit:
I've updated the code to include the other requirements and moved finding the last cell to within the loop so it actually works.
Note:
Mid(sFileName, InStr(sFileName, "1010EL") - 3, 3) - this code will throw an error if the text doesn't contain 1010EL. Add a check that InStr(sFileName, "1010EL") <> 0 before letting that line execute.
I have this code that gets all file types.
Dim file as variant
file = Application.GetOpenFilename("All Files, *.*", , "Select File", , True)
Then I have to print it in the cells on a sheet.
For i = 1 To UBound(file)
lRow = Cells(Rows.count, 15).End(xlUp).Row
lRow = lRow + 1
ThisWorkbook.Sheets("Main").Range("O" & lRow).Value = CStr(file(i))
Next i
but what I want is first check the contents of the array. If the array has this file type, then I have to remove it in the arraylist. After that, a message will pop out that this files are removed.
dim arr() as string
arr = Split("ade|adp|app|asp|bas|bat|cer|chm|cmd|com|cpl|crt|csh|der|exe|fxp|gadget|hlp|hta|inf|ins|isp|its|js|jse|" _
& "ksh|lnk|mad|maf|mag|mam|maq|mar|mas|mat|mau|mav|maw|mda|mdb|mde|mdt|mdw|mdz|msc|msh|msh1|msh2|" _
& "mshxml|msh1xml|msh2xml|ade|adp|app|asp|bas|bat|cer|chm|cmd|com|cpl|crt|csh|der|exe|fxp|gadget|hlp|" _
& "hta|msi|msp|mst|ops|pcd|pif|plg|prf|prg|pst|reg|scf|scr|sct|shb|shs|ps1|ps1xml|ps2|ps2xml|psc1|psc2|tmp|url|vb|vbe|vbs|vsmacros|vsw|ws|wsc|wsf|wsh|xnk", "|")
I just don't know where I have to start. I have found a little bit same problem here in this post, but I just can't understand it. Thanks!
You can use a RegExp and a varaint array to do this quickly
This code looks for path... dot extension end string so it is more robust than your current array which may remove files based on the path name rather than file type
Sub B()
Dim fName As Variant
Dim objRegex As Object
Dim lngCnt As Long
Dim rng1 As Range
Set objRegex = CreateObject("vbscript.regexp")
On Error Resume Next
fName = Application.GetOpenFilename("All Files, *.*", , "Select file", , True)
If Err.Number <> 0 Then Exit Sub
On Error GoTo 0
With objRegex
.Pattern = ".*\.(ade|adp|app|asp|bas|bat|cer|chm|cmd|com|cpl|crt|csh|der|exe|fxp|gadget|hlp|hta|inf|ins|isp|its|js|jse|" _
& "ksh|lnk|mad|maf|mag|mam|maq|mar|mas|mat|mau|mav|maw|mda|mdb|mde|mdt|mdw|mdz|msc|msh|msh1|msh2|" _
& "mshxml|msh1xml|msh2xml|ade|adp|app|asp|bas|bat|cer|chm|cmd|com|cpl|crt|csh|der|exe|fxp|gadget|hlp|" _
& "hta|msi|msp|mst|ops|pcd|pif|plg|prf|prg|pst|reg|scf|scr|sct|shb|shs|ps1|ps1xml|ps2|ps2xml|psc1|psc2|tmp|url|vb|vbe|vbs|vsmacros|vsw|ws|wsc|wsf|wsh|xnk)$"
`replace matching file types with blank array entries
For lngCnt = 1 To UBound(fName)
fName(lngCnt) = .Replace(fName(lngCnt), vbNullString)
Next
End With
Set rng1 = Cells(Rows.Count, 15).End(xlUp).Offset(1,0)
'dump array to sheet
rng1.Resize(UBound(fName), 1) = Application.Transpose(fName)
` remove blank entries
On Error Resume Next
rng1.SpecialCells(xlCellTypeBlanks).Delete xlUp
On Error GoTo 0
End Sub
One way would be to check that the extension it's not present in the blacklist with InStr:
Const exts = _
".ade.adp.app.asp.bas.bat.cer.chm.cmd.com.cpl.crt.csh.der.exe.fxp.gadget" & _
".hlp.hta.inf.ins.isp.its.js.jse.ksh.lnk.mad.maf.mag.mam.maq.mar.mas.mat" & _
".mau.mav.maw.mda.mdb.mde.mdt.mdw.mdz.msc.msh.msh1.msh2.mshxml.msh1xml" & _
".msh2xml.ade.adp.app.asp.bas.bat.cer.chm.cmd.com.cpl.crt.csh.der.exe.fxp" & _
".gadget.hlp.hta.msi.msp.mst.ops.pcd.pif.plg.prf.prg.pst.reg.scf.scr.sct" & _
".shb.shs.ps1.ps1xml.ps2.ps2xml.psc1.psc2.tmp.url.vb.vbe.vbs.vsmacros.vsw" & _
".ws.wsc.wsf.wsh.xnk."
Dim file As Variant
file = Application.GetOpenFilename("All Files, *.*", , "Select File", , True)
Dim i As Long, data(), count As Long, ext As String
ReDim data(1 To UBound(file) + 1, 1 To 1)
' filter the list
For i = LBound(file) To UBound(file)
ext = LCase(Mid(file(i), InStrRev(file(i), ".")))
If InStr(1, exts, ext & ".") = 0 Then ' if not blacklisted
count = count + 1
data(count, 1) = file(i)
End If
Next
' copy the filtered list to the next available row in column "O"
If count Then
With ThisWorkbook.Sheets("Main").Cells(Rows.count, "O").End(xlUp)
.Offset(1).Resize(count).Value = data
End With
End If