I really hope someone can help me with this....
I have a macro at the moment that allows the user to input an 8 digit number and then the code searchs all .xls files in a specific folder until it finds that number. So far there are 61 files to search through and that number is getting bigger every day! My code works fine but it is a slow process and one that the user will be doing many times a day.
Desired outcome - the user will input a date, ie - 2013-10-28, which is the first part of a file name, then input a second date in the same format and then an 8 digit number. The macro will then open a preset folder, find the first file, open it and search for the 8 digit number. If the number is not found i want the macro to move to the next file in the folder until either the number is found or it reaches the second date defined folder at which point it will stop.
Worst case i'd like my existing macro to function the same but start with the most recently modified file and work backwards to cut down the running time.
This is what i have so far (vaCellvalue is the 8 digit number input by the user):-
Sub UKSearch()
Dim FSO As Object 'FileSystemObject
Set FSO = CreateObject("scripting.filesystemobject")
Dim Directory As String
Dim FileName As String
Dim varCellvalue As Long
Application.ScreenUpdating = False
MsgBox ("This may take a few minutes")
'value to be searched
varCellvalue = Range("D13").Value
'Change the directory below as needed
Directory = "\\**********\shared$\******\*******\********\"
If Right(Directory, 1) <> "\" Then
Directory = Directory & "\"
End If
'Search for all files in the directory with an xls* file type.
FileName = Dir(Directory & "*.xls*")
'Opens, searches through and closes each file
Do While FileName <> ""
OpenFile = Directory & FileName
Workbooks.Open (OpenFile)
Workbooks(FileName).Activate
'Count through all the rows looking for the required number
ActiveWorkbook.Sheets("UK Scan Sheet").Activate
LastRow = Range("B65536").End(xlUp).Row
intRowCount = LastRow
Range("B1").Select
For i = 1 To intRowCount
'If the required number is found then select it and stop the search
If ActiveCell.Value = varCellvalue Then
GoTo Finish
Else
End If
ActiveCell.Offset(1, 0).Select
Next i
Workbooks(FileName).Close
FileName = Dir
OpenFile = ""
Loop
Finish:
Application.ScreenUpdating = False
End Sub`
For anyone else out there who might one day ask this question here is the answer that i came up with in the end. Please be aware however as stated in my original question above, the dates involved here are file names - when the input box asks for a file creation date it is really asking the user for the first part of a file name that happens to always be a date.
Sub OpenByCreationDate()
Dim appShell As Object
Dim FileName As Variant
Dim FilePath As Variant
Dim oFolder As Object
Dim oFolderItem As Object
Dim TestDate As Variant
Dim IntCount As Variant
FolderPath = "\\cor-***-****\shared$\Common\Returns\**************\"
FileName = "*.xls*"
EnterDate:
TestDate = inputbox("Enter the file creation date below.")
If Not IsDate(TestDate) Then
MsgBox "The Date you entered is not valid." & vbCrLf _
& "Please enter the date again."
GoTo EnterDate
End If
SearchValue = inputbox("Enter the consignment number below.")
IntCount = 0
Set appShell = CreateObject("Shell.Application")
Set oFolder = appShell.Namespace(FolderPath)
For Each oFolderItem In oFolder.Items
If IntCount > 0 Then
TestDate = Left(oFolderItem.Name, 10)
Else
End If
If oFolderItem.Name Like TestDate & FileName Then
Workbooks.Open oFolderItem.Path
ActiveWorkbook.Sheets("UK Scan Sheet").Activate
LastRow = Range("B65536").End(xlUp).Row
intRowCount = LastRow
Range("B1").Select
For i = 1 To intRowCount
'If the required number is found then select it and stop the search
If ActiveCell.Value = SearchValue Then
ActiveCell.Select
MsgBox "Consignment number found."
GoTo Finish
Else
End If
ActiveCell.Offset(1, 0).Select
Next i
ActiveWorkbook.Close
IntCount = IntCount + 1
If IntCount = 10 Then
MsgBox "Consignment number could not be found, please try a different date."
Exit Sub
Else
End If
End If
Next oFolderItem
Finish:
End Sub
Related
First time I ask a question here, but so far answers from this forum have always helped me a lot. However, now I have been dealing with a problem for weeks and unfortunately never found sufficient answers.
The current task is to update an already existing macro regarding data processing and display to a newer UI and increased usability. However, in the same sense I would like to improve the speed of the macro.
My current problem is opening, loading, splitting and pasting multiple selected .txt files into appropriately named sheets. The files can very quickly have over a hundred thousand entries of data, all separated by either space or enter. For importing and splitting a single file, I stumbled across this code, which I have subsequently adapted for my circumstances:
Private Sub testModule1()
Dim arr, tmp, output
Dim Datei
Dim FSO
Dim x, y As Integer
Dim str_string, filePath As String
Set FSO = CreateObject("Scripting.FilesystemObject")
filePath = Application.GetOpenFilename
Set Datei = FSO.OpentextFile(filePath)
str_string = Datei.readall
Datei.Close
arr = Split(str_string, vbCrLf)
ReDim output(UBound(arr), 50)
For x = 0 To UBound(arr)
tmp = Split(arr(x), " ")
For y = 0 To UBound(tmp)
output(x, y) = tmp(y)
Next
Next
Sheets("Sheet1").Range("A1").Resize(UBound(output) + 1, UBound(output, 2)) = output
End Sub
This part lets me select a single file, splits the cells as desired, and finally posts it to the first sheet.
For importing multiple files and naming the sheet after the file name, I found code here (the first solution):
https://www.mrexcel.com/board/threads/importing-multiple-text-files-in-to-multiple-work-sheets-with-text-file-names.1147363/
However, it currently opens in a new workbook, Windows tells me several times that data is overwritten when I do this, and the delimiter is also limited to only one character.
I am currently failing to find a reasonable combination of these two actions. The direct opening and reasonable splitting of several selected files and the subsequent integrating into several sheets named accordingly by file name.
In the old version of the macro, all file paths were first retrieved and stored in cells for this purpose, and later looped through these cells while reading and integrating the individual data in the process. However, everything in a sheet and rather, as I find, cumbersome.
I hope to find a more elegant solution for this problem than having to store data in sheets during editing and I am also happy about other suggestions and solutions.
EDIT:
After the hint from Solar Mike I was able to adapt the code to this:
Private Sub testModule2()
Dim fDialog As FileDialog
Dim fPath As Variant
Dim FSO
Dim Datei
Dim arr, tmp, output
Dim file, fileName As String
Dim x, y As Integer
Dim newSht As Worksheet
Application.ScreenUpdating = False
Set fDialog = Application.FileDialog(msoFileDialogFilePicker)
With fDialog
.AllowMultiSelect = True
.Title = "Please select files to import"
.Filters.Clear
.Filters.Add "VBO Files", "*.vbo"
If .Show = True Then
For Each fPath In .SelectedItems
Set FSO = CreateObject("Scripting.FilesystemObject")
fileName = FSO.GetFilename(fPath)
Set Datei = FSO.OpentextFile(fPath)
file = Datei.readall
Datei.Close
arr = Split(file, vbCrLf)
ReDim output(UBound(arr), 50)
For x = 0 To UBound(arr)
tmp = Split(arr(x), " ")
For y = 0 To UBound(tmp)
output(x, y) = tmp(y)
Next
Next
Set newSht = ActiveWorkbook.Sheets.Add(after:=ActiveWorkbook.Worksheets(ActiveWorkbook.Worksheets.Count))
newSht.Name = fileName
Sheets(fileName).Range("A1").Resize(UBound(output) + 1, UBound(output, 2)) = output
Next
End If
End With
Application.ScreenUpdating = True
End Sub
This does what is actually required, but just importing only 5 files already takes about a minute. Since on average up to 20 files can/should be imported and the processing of the data still takes place afterwards, this still seems a bit much to me.
It should be noted that the data sets are reduced again during processing, something between 40 and 80% of the data are filtered. Unfortunately I don't have the expertise to do this before, even if this would reduce the loading time.
Does this do what you want?
Sub CombineTextFiles()
'updateby Extendoffice
Dim xFilesToOpen As Variant
Dim I As Integer
Dim xWb As Workbook
Dim xTempWb As Workbook
Dim xDelimiter As String
Dim xScreen As Boolean
On Error GoTo ErrHandler
xScreen = Application.ScreenUpdating
Application.ScreenUpdating = False
xDelimiter = "|"
xFilesToOpen = Application.GetOpenFilename("Text Files (*.txt), *.txt", , "Kutools for Excel", , True)
If TypeName(xFilesToOpen) = "Boolean" Then
MsgBox "No files were selected", , "Kutools for Excel"
GoTo ExitHandler
End If
I = 1
Set xTempWb = Workbooks.Open(xFilesToOpen(I))
xTempWb.Sheets(1).Copy
Set xWb = Application.ActiveWorkbook
xTempWb.Close False
xWb.Worksheets(I).Columns("A:A").TextToColumns _
Destination:=Range("A1"), DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, _
ConsecutiveDelimiter:=False, _
Tab:=False, Semicolon:=False, _
Comma:=False, Space:=False, _
Other:=True, OtherChar:="|"
Do While I < UBound(xFilesToOpen)
I = I + 1
Set xTempWb = Workbooks.Open(xFilesToOpen(I))
With xWb
xTempWb.Sheets(1).Move after:=.Sheets(.Sheets.Count)
.Worksheets(I).Columns("A:A").TextToColumns _
Destination:=Range("A1"), DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, _
ConsecutiveDelimiter:=False, _
Tab:=False, Semicolon:=False, _
Comma:=False, Space:=False, _
Other:=True, OtherChar:=xDelimiter
End With
Loop
ExitHandler:
Application.ScreenUpdating = xScreen
Set xWb = Nothing
Set xTempWb = Nothing
Exit Sub
ErrHandler:
MsgBox Err.Description, , "Kutools for Excel"
Resume ExitHandler
End Sub
Unfortunately, after a bit more trial and error with my edited code, I haven't found a better way to optimize the process, so I'm posting the final code in response to the question.
The reduction of the amount of data is now done by a third party program and speeds up the processing sufficiently.
Option Explicit
Public Sub fileImporter()
Dim fDialog As FileDialog
Dim fPath As Variant
Dim FSO
Dim Data
Dim arr, tmp, output
Dim file, fileName As String
Dim x, y As Integer
Dim newSht As Worksheet
Application.ScreenUpdating = False
Set fDialog = Application.FileDialog(msoFileDialogFilePicker)
With fDialog
.AllowMultiSelect = True
.Title = "Please select files to import"
.Filters.Clear
.Filters.Add "VBO Files", "*.vbo" 'VBO Files are opened and handled like Text Files
If .Show = True Then
For Each fPath In .SelectedItems
Set FSO = CreateObject("Scripting.FilesystemObject")
fileName = FSO.GetFilename(fPath)
Set Data = FSO.OpentextFile(fPath)
file = Data.readall
Data.Close
arr = Split(file, vbCrLf)
ReDim output(UBound(arr), 50)
For x = 0 To UBound(arr)
tmp = Split(arr(x), " ")
For y = 0 To UBound(tmp)
output(x, y) = tmp(y)
Next
Next
Set newSht = ActiveWorkbook.Sheets.Add(after:=ActiveWorkbook.Worksheets(ActiveWorkbook.Worksheets.Count))
newSht.Name = fileName
Sheets(fileName).Range("A1").Resize(UBound(output) + 1, UBound(output, 2)) = output
Next
End If
End With
Application.ScreenUpdating = True
End Sub
Thanks for all the help and I hope this can help someone else too.
I have more than 300 file names.
I need to find that files by name and move to other location
I have try to search with OR between file names but from all list only 7 files come up
Any ideas how to do it fast?
I can't find any macro command with this
thanks
import shutil,os
for i in os.listdir(dirname):
if filenamelist.__contains__(i):
shutil.copy(dirname+'/'+i,locationtocopyto)
is probably what you want.
I found this
and It's working
Sub copyfiles()
'Updateby Extendoffice
Dim xRg As Range, xCell As Range
Dim xSFileDlg As FileDialog, xDFileDlg As FileDialog
Dim xSPathStr As Variant, xDPathStr As Variant
Dim xVal As String
On Error Resume Next
Set xRg = Application.InputBox("Please select the file names:", "KuTools For Excel", ActiveWindow.RangeSelection.Address, , , , , 8)
If xRg Is Nothing Then Exit Sub
Set xSFileDlg = Application.FileDialog(msoFileDialogFolderPicker)
xSFileDlg.Title = "Please select the original folder:"
If xSFileDlg.Show <> -1 Then Exit Sub
xSPathStr = xSFileDlg.SelectedItems.Item(1) & "\"
Set xDFileDlg = Application.FileDialog(msoFileDialogFolderPicker)
xDFileDlg.Title = "Please select the destination folder:"
If xDFileDlg.Show <> -1 Then Exit Sub
xDPathStr = xDFileDlg.SelectedItems.Item(1) & "\"
For Each xCell In xRg
xVal = xCell.Value
If TypeName(xVal) = "String" And xVal <> "" Then
FileCopy xSPathStr & xVal, xDPathStr & xVal
End If
Next
End Sub
Want to check if there is a worksheet with the same name as the file.
At the moment I have filnam opening the files as an array but want it to cycle through the code and see if there is a worksheet with the same name.
I have used a split to remove the path name and the extension but cant get it to check.
I apologise for the messiness of the code. Been trying to get it sorted then Ill tidy it up. There is more code but that isnt required for this as I want it to run that code if there isnt a match.
Please can you help?
Sub sort_it_out()
Dim wb1 As Workbook
Dim wb2 As Workbook
Dim Sheet As Worksheet
Dim filnam As Variant
On Error GoTo errorhandler
Set wb1 = ActiveWorkbook
ChDir Application.ActiveWorkbook.path
'get files
filnam = Application.GetOpenFilename(FileFilter:="2D Table Formats (*.htm;*.xlsm;*.html),*.htm;*.xlsm;*.html", Title:="Select 2D Table", MultiSelect:=True)
'set the array
If IsArray(filnam) Then 'if at least one file is selected, this will be an Array
'define j as the array
For j = LBound(filnam) To UBound(filnam)
'remove path and extension
Dim s As String, a() As String, p As String
s = filnam(j)
a() = Split(s, "\")
p = Split(a(UBound(a)), ".")(0)
MsgBox "p " & p
'check if worksheet exists
For Each ws_check In ThisWorkbook.Worksheets()
If ws_check.Name = p Then
MsgBox "Its there"
Exit Sub
Else
End If
Next ws_check
'continue code from here
This then runs the code... but its not looping the array for some reason. Only one file at at a time. Can you please help?
It is a little hard to follow your code but does this do what you are trying to do?
I think you were storing the file name in the p variable so my code below would check each worksheet in the workbook to see if they have the same name as the p variable.
Public Sub CompareWorksheetNamesToFiles()
Dim file_name As String
file_name = ActiveWorkbook.Name
Dim ws_check As Worksheet
For Each ws_check In ThisWorkbook.Worksheets()
If ws_check.Name = p Then
Debug.Print ("Do Something")
End If
Next ws_check
End Sub
I have worked it all out now.
This will now open file locations, shorten their paths to just the filename minus the extension, then ws check checks the sheets against the filename and then looper jumps to the next.
Thank you to alwaysdata for helping me out.
Sub sort_it_out()
Dim filnam As Variant
'open file locations
filnam = Application.GetOpenFilename(FileFilter:="2D Table Formats (*.htm;*.xlsm;*.html),*.htm;*.xlsm;*.html", Title:="Select 2D Table", MultiSelect:=True)
'if at least one file is selected, this will be an Array
If IsArray(filnam) Then
For j = LBound(filnam) To UBound(filnam)
'remove pathway and extension from entire filename and path. ie C:\open.txt becomes open.
Dim s As String, a() As String, p As String
s = filnam(j)
a() = Split(s, "\")
p = Split(a(UBound(a)), ".")(0)
'check if worksheet exists against p ... ie if theres a worksheet called open it will goto the next option if not it will continue through code
For Each ws_check In ThisWorkbook.Worksheets()
If ws_check.Name = p Then
MsgBox p & " has already been transfered across. ", vbExclamation 'lets the user know this is already there.
GoTo looper
Else
End If
Next ws_check
'do something here with the code if not found. IE MSGBOX " NOT FOUND "
'jump to this point if there is a match.
looper:
Next
Else
Exit Sub
End If
End Sub
Could someone tell me if it is possible for a user to input two seperate dates into input boxes and then search a folder for files with (ideally) create dates that fall between the input dates?
I can do a search through files in a folder fine but the number of files is increasing every day and the time to run a search through all of them is getting longer. I'm hopeing that if the user can select a date range then this will cut down the time to run.
If that isn't possible at all is it possible to set a macro to search through files in a folder STARTING with the most recently created and then working back from there?
Sub UKSearch()
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Search function to find specific consignment number from multiple intake sheets'
'Used by Traffic Office '
'Created by *********** 11/03/14 Password to unlock = ********* '
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Dim FSO As Object 'FileSystemObject
Set FSO = CreateObject("scripting.filesystemobject")
Dim Directory As String
Dim FileName As String
Dim varCellvalue As Long
Application.ScreenUpdating = False
MsgBox ("This may take a few minutes")
'value to be searched
varCellvalue = Range("D13").Value
'Change the directory below as needed
Directory = "\\*******\shared$\Common\Returns\*********\"
If Right(Directory, 1) <> "\" Then
Directory = Directory & "\"
End If
'Search for all files in the directory with an xls* file type.
FileName = Dir(Directory & "*.xls*")
''''''''''''''''''''''''
'Opens, searches through and closes each file
Do While FileName <> ""
OpenFile = Directory & FileName
Workbooks.Open (OpenFile)
Workbooks(FileName).Activate
'Count through all the rows looking for the required number
ActiveWorkbook.Sheets("UK Scan Sheet").Activate
LastRow = Range("B65536").End(xlUp).Row
intRowCount = LastRow
Range("B1").Select
For i = 1 To intRowCount
'If the required number is found then select it and stop the search
If ActiveCell.Value = varCellvalue Then
GoTo Finish
Else
End If
ActiveCell.Offset(1, 0).Select
Next i
Workbooks(FileName).Close
FileName = Dir
OpenFile = ""
Loop
''''''''''''''''''''''''''
Finish:
Application.ScreenUpdating = False
End Sub
Add to your dim section:
Dim oFile
Before your loop add:
Set oFile = CreateObject("Scripting.FileSystemObject")
In your loop before you open the file add an if statement:
if oFile.getFile(Directory & FileName).DateCreated >= EarliestDate and oFile.getFile(Directory & FileName).DateCreated <= LatestDate
You can also use oFile.getFile(Directory & FileName).DateLastModified - if you want to use the last change date of file instead of creation date.
I've got lots of files in a folder structered with names like:
"prof102122013#10.18.41.csv"
where the "02122013" bit is the date - 02/12/2013. Some of them have been made on the same day. I'd like to create a file that takes all of the workbooks that were made on the same day and put them all in one big file. So far I am struggling to get the selectivity to open a day-specific file. Does anyone have any idea what kind of code can help me with this?
Edit: Solved, thanks for the help, all! Here was the code that worked for me:
folder_location = Application.ActiveWorkbook.Path
i2 = 0
strFile = Dir(folder_location & "\")
'looping through to find the right file names and putting them all in an array
While strFile <> ""
If Right(strFile, 3) = "csv" Then
file_to_analyse = Split(strFile, "#")
If Right(file_to_analyse(0), 8) = date_we_want_to_analyse_on Then
found_files_to_analyse(i2) = strFile
i2 = i2 + 1
End If
End If
strFile = Dir
Wend
Do you want to consolidate files on the basis of file saved date or on the basis of the name of the file. A file named with yesterday's date can be saved today and will bear today's date. I guess you would have to parse the name of the file and apply logic around the date (in the file name) in a do while loop till all the files in the directory are searched for the condition. If the condition is met, you copy the opened file into a worksheet in your file. If the condition is not met, the file is skipped. Following might help
For each date which needs to be consolidated, do the following in a loop or an in a user prompted message box where the user inputs the date. You also need to chose whether you want the consolidation to happen in the workbook from where you are launching the macro or a separately opened workbook. The code below assumes you are consolidating in the same workbook.
Path = Path of the directory in which the files are stored
Flname = Dir(Path & "*.csv")
Do While Flname <> ""
If ' file check Condition' Then
Filecheckname = True ' Checks if file follows the naming conventions desired
Else
Filecheckname = False
End If
If Filecheckname Then
FlDate = getDate(Flname) ' extracts the date from the file name
Else
GoTo Errorhandler ' If there is an error, then the macro stops with a message to the user
End If
If FlDate<> Date Then
flsskpd = flsskpd + 1 ' If the date criteria is not met, the file is skipped with an increment to the fileskipped counter
Flname = Dir()
Else
Workbooks.Open Filename:=Path & Flname, ReadOnly:=True
'Code to Copy into consolidated workbook (ThisWorkbook)
filesmoved = filesmoved + 1
Flname = Dir()
End if
Loop
Message to user about how many files skipped and consolidated.
Prompt user whether to continue to the next date consolidation, if yes, continue or take the new date as an input and repeat the loop
If you want VBA to "search" for a file/folder in a directory, I think you need to use something like this:
Option Explicit
Option Compare Text
Public Enum xlSearchMode
xlFilesOnly = 0
xlFoldersOnly = 1
xlFilesAndFolders = 2
End Enum
Function SearchInDirectory(FName As String, Optional FoName As String, Optional SearchMode As xlSearchMode = xlFilesOnly, Optional ExactMatch As Boolean = True) As Variant
'By Abdallah Khaled Ali El-Yaddak
'Returns an array of strings with files/folders matching what you are searching for.
'If nothing is found, it returns an array of one empty string element.
'-------------'
'FName (String): The file/folder to look for
'[FoName] (String): The directory to search in, if omitted, CurDir will be used.
'[SreachMode] (xlSearchMode): xlFilesOnly (default) = Look for files only | xlFoldersOnly = Look for folders only | xlFilesAndFolders = Look for both
'[Exactmatch] (Boolean): True (default) = Look only for this string (case insenstive) | False = Sreach for any files/folders that includes this string in their name
Dim FSO As Object, File As Object, Folder As Object, Fnames() As String, i As Long, SubNames As Variant, SubFolder As Object
If FoName = "" Then FoName = CurDir
If Right(FoName, 1) <> "\" Then FoName = FoName & "\"
ReDim Fnames(1 To 1) As String
Set FSO = CreateObject("Scripting.FileSystemObject")
Set Folder = FSO.GetFolder(FoName)
If SearchMode = xlFilesOnly Or SearchMode = xlFilesAndFolders Then
For Each File In FSO.GetFolder(Folder).Files
If (ExactMatch And SubFolder.Name = FName) Or _
(Not ExactMatch And SubFolder.Name Like "*" & FName & "*") Then
Fnames(UBound(Fnames)) = File.Path
ReDim Preserve Fnames(1 To UBound(Fnames) + 1)
End If
Next
End If
If SearchMode = xlFoldersOnly Or SearchMode = xlFilesAndFolders Then
For Each SubFolder In FSO.GetFolder(Folder).subFolders
If (ExactMatch And SubFolder.Name = FName) Or _
(Not ExactMatch And SubFolder.Name Like "*" & FName & "*") Then
Fnames(UBound(Fnames)) = SubFolder.Path
ReDim Preserve Fnames(1 To UBound(Fnames) + 1)
End If
Next
End If
For Each SubFolder In FSO.GetFolder(Folder).subFolders
SubNames = SearchInDirectory(FName, SubFolder.Path, SearchMode, ExactMatch)
If SubNames(LBound(SubNames)) <> "" Then
For i = LBound(SubNames) To UBound(SubNames)
Fnames(UBound(Fnames)) = SubNames(i)
ReDim Preserve Fnames(1 To UBound(Fnames) + 1)
Next
End If
Next
If UBound(Fnames) > 1 Then ReDim Preserve Fnames(1 To UBound(Fnames) - 1)
SearchInDirectory = Fnames
End Function
To test, you need something like this:
Sub Test()
Dim a As Variant, i As Long
a = SearchInDirectory(date_we_want_to_analyse_on, folder_location, xlFilesOnly, Flase)
For i = LBound(a) To UBound(a)
Debug.Print a(i)
Next
End Sub
Notes:
This solution doesn't work on MAC (tested only on windows)
Searching will take longer for larger directories (The number of files/folders inside)