I am trying to list all my folders from a drive in a directory onto an excel spreadsheet with a touch of a button. I made the button and assigned this macro... why won't it compile? The *** **** shows what they debugged. Said object folder was not an object. Please help!
Sub ListAllFile()
Dim objFSO As Object
Dim objFolder As Object
Dim objFile As Object
Dim ws As Worksheet
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set ws = Worksheets.Add
'Get the folder object associated with the directory
***Set objFolder = fso.GetFolder("C:hello\EMILY")***
ws.Cells(1, 1).Value = objFolder.Name
'Loop through the Files collection
For Each objFile In objFolder.Files
ws.Cells(ws.UsedRange.Rows.Count + 1, 1).Value = objFile.Name
Next
End Sub
This will allow you to get the folder names, unless you actually want files. It was modified from your original code. I commented out the excel/worksheet logic.
Part of the problem was fso.GetFolder was not an object which was declared and set. If you want still want files, you can change objFolder.Subfolders to .Files
Sub ListAllFile()
Dim objFSO As Object
Dim objFolder As Object
Dim objFile As Object
Dim ws As Worksheet
Set objFSO = CreateObject("Scripting.FileSystemObject")
'Set ws = Worksheets.Add
'Get the folder object associated with the directory
Set objFolder = objFSO.GetFolder("C:\users")
'ws.Cells(1, 1).Value = objFolder.Name
'Loop through the Files collection
For Each objFile In objFolder.subfolders
MsgBox objFile.Name ' to test output
'ws.Cells(ws.UsedRange.Rows.Count + 1, 1).Value = objFile.Name
Next
End Sub
There are many ways to do this. Here is one way.
Option Explicit
Sub FileListingAllFolder()
Dim pPath As String
Dim FlNm As Variant
Dim ListFNm As New Collection ' create a collection of filenames
Dim OWb As Workbook
Dim ShtCnt As Integer
Dim Sht As Integer
Dim MWb As Workbook
Dim MWs As Worksheet
Dim i As Integer
' Open folder selection
With Application.FileDialog(msoFileDialogFolderPicker)
.Title = "Select a Folder"
.AllowMultiSelect = False
If .Show <> -1 Then GoTo NextCode
pPath = .SelectedItems(1)
End With
Application.WindowState = xlMinimized
Application.ScreenUpdating = False
' Create master workbook with single sheets
Set MWb = Workbooks.Add(1)
MWb.Sheets(1).Name = "Result"
Set MWs = MWb.Sheets("Result")
Cells(1, 1) = "No."
Cells(1, 2) = "Sheet Name"
Cells(1, 3) = "File Name"
Cells(1, 4) = "Link"
i = 2
' Filling a collection of filenames (search Excel files including subdirectories)
Call FlSrch(ListFNm, pPath, "*.xls", True)
' Print list to immediate debug window and as a message window
For Each FlNm In ListFNm ' cycle for list(collection) processing
'Start Processing here
Set OWb = Workbooks.Open(FlNm)
ShtCnt = ActiveWorkbook.Sheets.Count
For Sht = 1 To ShtCnt
MWs.Cells(i, 1) = i - 1
MWs.Cells(i, 2) = Sheets(Sht).Name
MWs.Cells(i, 3) = OWb.Name
MWs.Cells(i, 4).Formula = "=HYPERLINK(""" & FlNm & """,""Click Here"")"
i = i + 1
Next Sht
'End file processing file
OWb.Close False
Next FlNm
' Print to immediate debug window and message if no file was found
If ListFNm.Count = 0 Then
Debug.Print "No file was found !"
MsgBox "No file was found !"
MWb.Close False
End
End If
MWb.Activate
MWs.Activate
Cells.Select
Selection.EntireColumn.AutoFit
Range("A1").Select
Application.ScreenUpdating = True
Application.WindowState = xlMaximized
End
NextCode:
MsgBox "You Click Cancel, and no folder selected!"
End Sub
Private Sub FlSrch(pFnd As Collection, pPath As String, pMask As String, pSbDir As Boolean)
Dim flDir As String
Dim CldItm As Variant
Dim sCldItm As New Collection
' Add backslash at the end of path if not present
pPath = Trim(pPath)
If Right(pPath, 1) <> "\" Then pPath = pPath & "\"
' Searching files accordant with mask
flDir = Dir(pPath & pMask)
Do While flDir <> ""
pFnd.Add pPath & flDir 'add file name to list(collection)
flDir = Dir ' next file
Loop
' Procedure exiting if searching in subdirectories isn't enabled
If Not pSbDir Then Exit Sub
' Searching for subdirectories in path
flDir = Dir(pPath & "*", vbDirectory)
Do While flDir <> ""
' Add subdirectory to local list(collection) of subdirectories in path
If flDir <> "." And flDir <> ".." Then If ((GetAttr(pPath & flDir) And _
vbDirectory) = 16) Then sCldItm.Add pPath & flDir
flDir = Dir 'next file
Loop
' Subdirectories list(collection) processing
For Each CldItm In sCldItm
Call FlSrch(pFnd, CStr(CldItm), pMask, pSbDir) ' Recursive procedure call
Next
End Sub
Also, check out the link below.
http://www.learnexcelmacro.com/wp/download/
Save the file from the link named 'File Manager (Excel Workbook)'. That is a very cool app!!
Related
I want to do the following:
Prompt user to choose a folder
Loop through folder (and subfolders if they exist)
Get all .xlsx files
Get specific column from those files (all have the same structure) and combine data from that column
I get all subfolders and all files but I get 5 times as much as I should.
L column is where I get all my data and Insert into Identical Master File (into L column).
I have 5 files - I should get 5 items in the last column, I simply add new folder in it, and same files(copied), so now I should get 10 items in the last column, instead I get 50.
Sub LoopThroughFolder()
Dim MyFile As String, Str As String, MyDir As String, Wb As Workbook
Dim Rws As Long, Rng As Range, r As Range
Set Wb = ThisWorkbook: Wb.Sheets(2).Range("L:L").ClearContents
Dim FSO As Object, fld As Object, Fil As Object
Dim wbkCS As Workbook
Dim FolderPath As String
Dim fsoFile As Object
Dim fsoFol As Object
Dim fileName As String
Dim sWb As Workbook
Dim MatchingColumn As Range
Dim MatchingRowNb As Long
MsgBox "Choose a folder: "
Application.DisplayAlerts = False
With Application.FileDialog(msoFileDialogFolderPicker)
.InitialFileName = "C:\Users\"
.AllowMultiSelect = False
If .Show <> -1 Then
MsgBox "No folder selected! Exiting script."
Exit Sub
End If
FolderPath = .SelectedItems(1)
End With
If Right(FolderPath, 1) <> "\" Then
FolderPath = FolderPath + "\"
End If
Set FSO = CreateObject("Scripting.FileSystemObject")
Set fld = FSO.GetFolder(FolderPath)
If FSO.FolderExists(fld) Then
For Each fsoFol In FSO.GetFolder(FolderPath).SubFolders
For Each fsoFile In fsoFol.Files
If Mid(fsoFile.Name, InStrRev(fsoFile.Name, ".") + 1) = "xlsx" Then
fileName = fsoFile.Name
Application.ScreenUpdating = False
MyDir = FolderPath 'fld
fileName = Dir(MyDir & "*.xlsx")
ChDir MyDir
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Do While fileName <> ""
Set sWb = Workbooks.Open(fileName)
With sWb.Worksheets(2)
Rws = .Cells(Rows.Count, 12).End(xlUp).Row
Set Rng = Range(.Cells(5, 1), .Cells(Rws, 12))
End With
With Wb.Worksheets(2)
Set MatchingColumn = .Range(.Cells(5, 1), .Cells(.Rows.Count, 1).End(xlUp))
For Each r In Rng.Rows
If r.Cells(1, 1).Value2 <> vbNullString Then 'Ignoring empty rows
If r.Rows.Hidden = False Then
'We find the row where the Ids matche
MatchingRowNb = Application.Match(r.Cells(1, 1).Value2, MatchingColumn, False)
'We add the current value in the cell with the new value comming from the other file
.Cells(4 + MatchingRowNb, 12).Value2 = .Cells(4 + MatchingRowNb, 12).Value2 + r.Cells(1, 12).Value2
End If
End If
Next
End With
sWb.Close SaveChanges:=True
Application.DisplayAlerts = True
fileName = Dir()
Loop
End If
Next
Next
End If
End Sub
You're using both FSO and Dir() to loop over the files, so that's why you're getting the same files over and over.
When your sub ends up doing a bunch of things (particularly when one thing is nested in another, and so on) then it's best to consider splitting it up, so you can concentrate on the one thing that's giving you problems, without all the other things "getting in the way".
Here's a stripped-down version to show what I mean. It works but for clarity doesn't have your file processing code.
Option Explicit
Sub LoopThroughFolder()
Dim Wb As Workbook, sWb As Workbook
Dim FolderPath As String
Dim colFiles As Collection, f
'get a folder
FolderPath = ChooseFolder()
If Len(FolderPath) = 0 Then
MsgBox "No folder selected: exiting"
Exit Sub
End If
'find all excel files in subfolders of that folder
Set colFiles = FileMatches(FolderPath, "*.xlsx")
If colFiles.Count = 0 Then
MsgBox "No xlsx files found"
Exit Sub
End If
Set Wb = ThisWorkbook
Wb.Sheets(2).Range("L:L").ClearContents
'loop over the files we found
For Each f In colFiles
Set sWb = Workbooks.Open(f.Path)
'process the file here
sWb.Close SaveChanges:=True
Next f
End Sub
Function ChooseFolder() As String
With Application.FileDialog(msoFileDialogFolderPicker)
.Title = "Choose a folder"
.InitialFileName = "C:\Users\"
.AllowMultiSelect = False
If .Show = -1 Then
ChooseFolder = .SelectedItems(1)
If Right(ChooseFolder, 1) <> "\" Then _
ChooseFolder = ChooseFolder + "\"
End If
End With
End Function
'Return a collection of file objects given a starting folder and a file pattern
' e.g. "*.txt"
'Pass False for last parameter if don't want to check subfolders
Function FileMatches(startFolder As String, filePattern As String, _
Optional subFolders As Boolean = True) As Collection
Dim fso, fldr, f, subFldr
Dim colFiles As New Collection
Dim colSub As New Collection
Set fso = CreateObject("scripting.filesystemobject")
colSub.Add startFolder
Do While colSub.Count > 0
Set fldr = fso.getfolder(colSub(1))
colSub.Remove 1
For Each f In fldr.Files 'get files in folder
If UCase(f.Name) Like UCase(filePattern) Then colFiles.Add f
Next f
If subFolders Then 'get subfolders for processing?
For Each subFldr In fldr.subFolders
colSub.Add subFldr.Path
Next subFldr
End If
Loop
Set FileMatches = colFiles
End Function
Trying to find MS Excel/VBA code to move all subfolders with lastdatemodified < date -30 to a different folder.
Like this (but obviously not this)
foldertomove = subfolder
folder = main
newfolder = archive
for each subfolder in main
if subfolder.datelastmodified < date - 30 then
move subfolder to archive
end if
next
Any help is greatly appreciated! Thanks!
Objective of this program is to Copy Folders, Sub-Folders and Folders
within Folders along with files contained in them. It could be any type of the file PDF, Text, Word, Excel etc.
This program will only copy Files which are 30 days older from
Current Time. User can adjust this date or between two dates as per
his requirements.
When program is run File Picker Dialog will open and allow user to
chose the folder to be archived.
It is very important that an Empty Directory Structure with same
folder structure as parent folder to be archived has is created.
Presently VBA code for this step has not been incorporated in this
program. Simplest way is to copy paste folder and then delete files
in various folders and sub-folders manually. It is one time exercise
so long as parent directory structure remains the same. Any changes
in the parent directory structure are also to be incorporated in the
Archive folder also.
Program will also output Directory and File Paths on a separate
workbook of the parent directory being archived. If it is not
required then relevant portions of the program can be commented out.
Snapshot of output is placed below.
Further improvements in this program shall be endeavoured based on feedback and help of experts.
Code is placed below.
Sub CopyFolders_Recursively()
Dim strFolder As String
Dim objFSO As Object
Dim objFolder As Object
Dim myResults As Variant
Dim lCount As Long
Set objFSO = CreateObject("Scripting.FileSystemObject")
' Get the directory from the user
With Application.FileDialog(msoFileDialogFolderPicker)
.Show
If .SelectedItems.Count = 0 Then Exit Sub
'user cancelled
strFolder = .SelectedItems(1)
End With
Set objFolder = objFSO.GetFolder(strFolder)
'the variable dimension has to be the second one
ReDim myResults(0 To 5, 0 To 0)
' place make some headers in the array
myResults(0, 0) = "Filename"
myResults(1, 0) = "Size"
myResults(2, 0) = "Created"
myResults(3, 0) = "Modified"
myResults(4, 0) = "Accessed"
myResults(5, 0) = "Full path"
'Send the folder to the recursive function
FillFileList objFolder, myResults, lCount
' Dump these to a worksheet
fcnDumpToWorksheet myResults
'tidy up
Set objFSO = Nothing
End Sub
Private Sub FillFileList(objFolder As Object, ByRef myResults As Variant, ByRef lCount As Long, Optional strFilter As String)
Dim i As Integer
Dim objFile As Object
Dim fsoSubFolder As Object
Dim fsoSubFolders As Object
Dim ToPath As String
Dim lpath As String
ToPath = "C:\Archive\"
Dim Fdtdiff As Integer
'load the array with all the files
For Each objFile In objFolder.Files
lCount = lCount + 1
ReDim Preserve myResults(0 To 5, 0 To lCount)
myResults(0, lCount) = objFile.Name
myResults(1, lCount) = objFile.Size
myResults(2, lCount) = objFile.DateCreated
myResults(3, lCount) = objFile.DateLastModified
myResults(4, lCount) = objFile.DateLastAccessed
myResults(5, lCount) = objFile.Path
Fdtdiff = DateValue(Now) - DateValue(myResults(3, lCount))
If Fdtdiff > 30 Then
lpath = Replace(objFile.Path, "my_dir", "Archive")
objFile.Copy lpath
End If
Next objFile
'recursively call this function with any subfolders
Set fsoSubFolders = objFolder.SubFolders
For Each fsoSubFolder In fsoSubFolders
FillFileList fsoSubFolder, myResults, lCount
Next fsoSubFolder
End Sub
Private Sub fcnDumpToWorksheet(varData As Variant, Optional mySh As Worksheet)
Dim iSheetsInNew As Integer
Dim sh As Worksheet, wb As Workbook
Dim myColumnHeaders() As String
Dim l As Long, NoOfRows As Long
If mySh Is Nothing Then
'make a workbook if we didn't get a worksheet
iSheetsInNew = Application.SheetsInNewWorkbook
Application.SheetsInNewWorkbook = 1
Set wb = Application.Workbooks.Add
Application.SheetsInNewWorkbook = iSheetsInNew
Set sh = wb.Sheets(1)
Else
Set mySh = sh
End If
'since we switched the array dimensions, have to transpose
With sh
Range(.Cells(1, 1), .Cells(UBound(varData, 2) + 1, UBound(varData, 1) + 1)) = _
Application.WorksheetFunction.Transpose(varData)
.UsedRange.Columns.AutoFit
End With
Set sh = Nothing
Set wb = Nothing
End Sub
Private Sub CopyFolders_Recursively()
Dim strFolder As String
Dim objFSO As Object
Dim objFolder As Object
Dim myResults As Variant
Dim lCount As Long
Set objFSO = CreateObject("Scripting.FileSystemObject")
' Get the directory from the user
'With Application.FileDialog(msoFileDialogFolderPicker)
'.Show
'If .SelectedItems.Count = 0 Then Exit Sub
'user cancelled
'strFolder = .SelectedItems(1)
'End With
strFolder = "D:\testing\" '<<change
Set objFolder = objFSO.GetFolder(strFolder)
'the variable dimension has to be the second one
ReDim myResults(0 To 5, 0 To 0)
' place make some headers in the array
myResults(0, 0) = "Filename"
myResults(1, 0) = "Size"
myResults(2, 0) = "Created"
myResults(3, 0) = "Modified"
myResults(4, 0) = "Accessed"
myResults(5, 0) = "Full path"
'Send the folder to the recursive function
FillFileList objFolder, myResults, lCount
' Dump these to a worksheet
fcnDumpToWorksheet myResults
CleanUpList
If Range("A2").Value = "" Then GoTo tidyup
AddFolders
Move_Folders
tidyup:
Cells.Delete
Range("A1").Select
'tidy up
Set objFSO = Nothing
End Sub
Private Sub FillFileList(objFolder As Object, ByRef myResults As Variant, ByRef lCount As Long, Optional strFilter As String)
Dim i As Integer
Dim objFile As Object
Dim fsoSubFolder As Object
Dim fsoSubFolders As Object
Dim lpath As String
Dim Fdtdiff As Integer
'load the array with all the files
For Each objFile In objFolder.Files
If InStr(objFile.Path, "~Archive") = 0 Then 'don't get files from the archive folder (assumes the archive folder is a subfolder of the folder from which you're moving the other subfolders
lCount = lCount + 1
ReDim Preserve myResults(0 To 5, 0 To lCount)
myResults(0, lCount) = objFile.Name
myResults(1, lCount) = objFile.Size
myResults(2, lCount) = objFile.DateCreated
myResults(3, lCount) = objFile.DateLastModified
myResults(4, lCount) = objFile.DateLastAccessed
myResults(5, lCount) = objFile.Path
'Fdtdiff = DateValue(Now) - DateValue(myResults(3, lCount))
'If Fdtdiff > 30 Then
'lpath = Replace(objFile.Path, "my_dir", "~Archive")
'objFile.Copy lpath
'End If
End If
Next objFile
'recursively call this function with any subfolders
Set fsoSubFolders = objFolder.SubFolders
For Each fsoSubFolder In fsoSubFolders
FillFileList fsoSubFolder, myResults, lCount
Next fsoSubFolder
End Sub
Private Sub fcnDumpToWorksheet(varData As Variant, Optional mySh As Worksheet)
'since we switched the array dimensions, have to transpose
With ThisWorkbook.Sheets(1) '<<change
Cells.ClearContents
Range(.Cells(1, 1), .Cells(UBound(varData, 2) + 1, UBound(varData, 1) + 1)) = _
Application.WorksheetFunction.Transpose(varData)
.UsedRange.Columns.AutoFit
End With
End Sub
Private Sub CleanUpList()
'sort most recent files to the top so when we remove dupes we'll be left with the most recent one
ThisWorkbook.Worksheets("Archive").Sort.SortFields.Clear '<<change sheet name
ThisWorkbook.Worksheets("Archive").Sort.SortFields.Add Key:=Range("D2:D65536") _
, SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:=xlSortNormal
With ThisWorkbook.Worksheets("Archive").Sort
.SetRange Range("A1:F65536")
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
'remove parent folder from path we'll check later
Columns("F:F").Replace What:="D:\testing\", Replacement:="", LookAt:=xlPart, MatchCase:=False '<< Change
'remove file name, leaving just the folder we want to move
Columns("F:F").Replace What:="\*", Replacement:="", LookAt:=xlPart, MatchCase:=False
'we just need one!
ThisWorkbook.Sheets(1).Range("$A$1:$AZ$65536").RemoveDuplicates Columns:=6, Header:=xlYes '<< remove dupes of folders to move
Set Rng = Range("D1:D100") '<< change if you know it will be less or more than 100
For Each cell In Rng
If cell.Value <> "" Then
If cell.Value > Date - 30 Then '<<only keep it if more than 30 days (or whatever you want)
cell.Value = ""
End If
End If
Next
On Error Resume Next
Columns("D:D").SpecialCells(xlCellTypeBlanks).EntireRow.Delete
On Error GoTo 0
End Sub
Private Sub AddFolders() 'we'll archive by year within the archive subfolder
Set Rng = Range("D2:D100") '<< change if you know it will be less or more than 100
For Each x In Rng
If x.Value <> "" Then
On Error Resume Next
MkDir "D:\testing\~Archive\" & Format(x.Value - 30, "yyyy") '<< Change
On Error GoTo 0
End If
Next x
End Sub
Private Sub Move_Folders()
'This example move the folder from FromPath to ToPath
Dim FSO As Object
Dim FromPath As String
Dim ToPath As String
Set Rng = Range("F2:F100") '<< change if you know it will be less or more than 100
For Each x In Rng
If x.Value <> "" Then
FromPath = "D:\testing\" & x.Value '<< Change
ToPath = "D:\testing\~Archive\" & Format(x.Offset(0, -2).Value - 30, "yyyy") & "\" & x.Value '<< Change
'Note: It is not possible to use a folder that exist in ToPath
'We created subfolders by year earlier so we can archive by year now
Set FSO = CreateObject("scripting.filesystemobject")
FSO.MoveFolder Source:=FromPath, Destination:=ToPath
End If
Next x
End Sub
Figured out a more direct way to get the subfolders needed to be archived:
Private Sub Archive_Hotel_Confs()
Sheets("Archiving").Select
Cells.ClearContents
Dim strStartPath As String
strStartPath = "W:testing\" 'ENTER YOUR START FOLDER HERE
ListHCFolder strStartPath
CleanUpList
If Range("A1").Value = "" Then GoTo tidyup
AddHCFolders
MoveHC_Folders
'tidy up
tidyup:
Cells.Delete
Range("A1").Select
Sheets("Last Run").Select
End Sub
Private Sub ListHCFolder(sFolderPath As String)
Dim FS As New FileSystemObject
Dim FSfolder As Folder
Dim subfolder As Folder
Dim i As Integer
Set FSfolder = FS.GetFolder(sFolderPath)
For Each subfolder In FSfolder.SubFolders
If InStr(subfolder.Name, "~Archive") = 0 Then
DoEvents
i = i + 1
'added this line
Cells(i, 1) = subfolder
Cells(i, 2) = subfolder.DateLastModified
'commented out this one
'Debug.Print subfolder
End If
Next subfolder
Set FSfolder = Nothing
End Sub
Private Sub CleanUpList()
Dim x As Variant
'remove parent folder from path we'll check later
Columns("A:A").Replace What:="W:testing\", Replacement:="", LookAt:=xlPart, MatchCase:=False '<< Change
Set Rng = Range(Range("B1"), Range("B" & Rows.Count).End(xlUp))
For Each x In Rng
If x.Value <> "" Then
If x.Value > Date - 30 Then '<<only keep it if more than 30 days (or whatever you want)
x.Value = ""
End If
End If
Next x
On Error Resume Next
Columns("B:B").SpecialCells(xlCellTypeBlanks).EntireRow.Delete
On Error GoTo 0
End Sub
Private Sub AddHCFolders() 'we'll archive by year within the archive subfolder
Dim x As Variant
Set Rng = Range(Range("B1"), Range("B" & Rows.Count).End(xlUp))
For Each x In Rng
If x.Value <> "" Then
On Error Resume Next
MkDir "W:testing\~Archive\" & Format(x.Value - 30, "yyyy") '<< Change
On Error GoTo 0
End If
Next x
End Sub
Private Sub MoveHC_Folders()
'This example move the folder from FromPath to ToPath
Dim FSO As Object
Dim FromPath As String
Dim ToPath As String
Dim x As Variant
Set Rng = Range(Range("A1"), Range("A" & Rows.Count).End(xlUp))
For Each x In Rng
If x.Value <> "" Then
FromPath = "W:testing\" & x.Value '<< Change
ToPath = "W:testing\~Archive\" & Format(x.Offset(0, 1).Value - 30, "yyyy") & "\" & x.Value '<< Change
'Note: It is not possible to use a folder that exist in ToPath
'We created subfolders by year earlier so we can archive by year now
Set FSO = CreateObject("scripting.filesystemobject")
FSO.MoveFolder Source:=FromPath, Destination:=ToPath
End If
Next x
End Sub
Listing files from a directory in an excel sheet? and adding hyperlinks to the results.
Added
"
With Application.FileDialog(msoFileDialogFolderPicker)
.AllowMultiSelect = False
.Show
On Error Resume Next
strTopFolderName = .SelectedItems(1)
Err.Clear
On Error GoTo 0
End With
"
This enabled used selection from a top directory.
Sub ListFiles()
'Set a reference to Microsoft Scripting Runtime by using
'Tools > References in the Visual Basic Editor (Alt+F11)
'Declare the variables
Dim objFSO As Scripting.FileSystemObject
Dim objTopFolder As Scripting.Folder
Dim strTopFolderName As String
'Insert the headers for Columns A through F
Range("A1").Value = "File Path"
Range("B1").Value = "File Size"
Range("C1").Value = "File Type"
Range("D1").Value = "Date Created"
Range("E1").Value = "Date Last Accessed"
Range("F1").Value = "Date Last Modified"
Range("G1").Value = "Original Document Date"
'Assign the top folder to a variable
strTopFolderName = "Y:\master-documentation" 'want to be user selectable!
'Create an instance of the FileSystemObject
Set objFSO = CreateObject("Scripting.FileSystemObject")
'Get the top folder
Set objTopFolder = objFSO.GetFolder(strTopFolderName)
'Call the RecursiveFolder routine
Call RecursiveFolder(objTopFolder, True)
'Change the width of the columns to achieve the best fit
Columns.AutoFit
End Sub
Sub RecursiveFolder(objFolder As Scripting.Folder, _
IncludeSubFolders As Boolean)
'Declare the variables
Dim objFile As Scripting.File
Dim objSubFolder As Scripting.Folder
Dim NextRow As Long
'Find the next available row
NextRow = Cells(Rows.Count, "A").End(xlUp).Row + 1
'Loop through each file in the folder
For Each objFile In objFolder.Files
Cells(NextRow, "A").Value = objFile.Path
Cells(NextRow, "B").Value = objFile.Size
Cells(NextRow, "C").Value = objFile.Type
Cells(NextRow, "D").Value = objFile.DateCreated
Cells(NextRow, "E").Value = objFile.DateLastAccessed
Cells(NextRow, "F").Value = objFile.DateLastModified
NextRow = NextRow + 1
Next objFile
'Loop through files in the subfolders
If IncludeSubFolders Then
For Each objSubFolder In objFolder.SubFolders
Call RecursiveFolder(objSubFolder, True)
Next objSubFolder
End If
End Sub
Not entirely sure of your question, but to select a folder, from Excel, you can use this code:
Dim sTopFolderName As String
With Application.FileDialog(msoFileDialogFolderPicker)
.AllowMultiSelect = False
.ButtonName = "Select Base Directory"
If .Show = 0 Then Exit Sub
sTopFolderName = .SelectedItems(1)
End With
'Force the explicit delcaration of variables
'Option Explicit
Sub Auto_Open()
Worksheets("Files").Columns(1).ClearContents
Worksheets("Files").Activate
'Set a reference to Microsoft Scripting Runtime by using
'Tools > References in the Visual Basic Editor (Alt+F11)
'Declare the variables
Dim objFSO As Scripting.FileSystemObject
Dim objTopFolder As Scripting.Folder
Dim strTopFolderName As String
With Application.FileDialog(msoFileDialogFolderPicker)
.AllowMultiSelect = False
.Show
On Error Resume Next
strTopFolderName = .SelectedItems(1)
Err.Clear
On Error GoTo 0
End With
If strTopFolderName = "" Then Exit Sub
'Insert the headers for Columns A through G
Range("A1").Value = "File Path"
'Range("B1").Value = "File Name"
'Range("C1").Value = "File Size"
'Range("D1").Value = "File Type"
'Range("E1").Value = "Date Created"
'Range("F1").Value = "Date Last Accessed"
'Range("G1").Value = "Date Last Modified"
'Assign the top folder to a variable
'strTopFolderName = "R:\RA\DM\Labetalol Tab\Dos\100+200mg\NP_BE"
'Create an instance of the FileSystemObject
Set objFSO = CreateObject("Scripting.FileSystemObject")
'Get the top folder
Set objTopFolder = objFSO.GetFolder(strTopFolderName)
'Call the RecursiveFolder routine
Call RecursiveFolder(objTopFolder, True)
'Change the width of the columns to achieve the best fit
'Columns.AutoFit
End Sub
Sub RecursiveFolder(objFolder As Scripting.Folder, _
IncludeSubFolders As Boolean)
'Declare the variables
Dim objFile As Scripting.File
Dim objSubFolder As Scripting.Folder
Dim NextRow As Long
'Find the next available row
NextRow = Cells(Rows.Count, "A").End(xlUp).Row + 1
'Loop through each file in the folder
For Each objFile In objFolder.Files
Cells(NextRow, "A").Value = objFile.Path
'Cells(NextRow, "B").Value = objFile.Name
'Cells(NextRow, "C").Value = objFile.Size
'Cells(NextRow, "D").Value = objFile.Type
'Cells(NextRow, "E").Value = objFile.DateCreated
'Cells(NextRow, "F").Value = objFile.DateLastAccessed
'Cells(NextRow, "G").Value = objFile.DateLastModified
NextRow = NextRow + 1
Next objFile
'Loop through files in the subfolders
If IncludeSubFolders Then
For Each objSubFolder In objFolder.SubFolders
Call RecursiveFolder(objSubFolder, True)
Next objSubFolder
End If
End Sub
This is exactly what we wanted to do! With a selection box for which directories to look at.
I have a macro that runs over a specified directory, creates a new summary workbook, and then copies selected data from all the excel files present (in the defined directory) into that summary workbook, it then saves the summary workbook into a new defined location and closes. I am obliged to change the directory name each time I have multiple folders for data merging, and sometimes over 30 directories.
I want this macro to loop automatically over several directories contained inside one root directory and perform the same operation detailed above. How can it be possible? I used the "scripting folder" method but it returned error when I ran the code...never got it worked!
Secondly, I want this macro to save the summary workbook with its folder name, the directory from which data is merged.
My code is here, please take a look and propose me a solution:
Sub MergeSitu()
Dim MyPath As String, FilesInPath As String
Dim MyFiles() As String
Dim SourceCcount As Long, FNum As Long
Dim mybook As Workbook, BaseWks As Worksheet
Dim sourceRange1 As Range, destrange1 As Range
Dim sourceRange2 As Range, destrange2 As Range
Dim sourceRange3 As Range, destrange3 As Range
Dim Rnum As Long, CalcMode As Long
Dim Cnum As Long
Dim listwb As Workbook
Dim mMonth As Range
' Change this to the path\folder location of the files.
MyPath = "D:\data\19h\13 feb\"
' Add a slash at the end of path if needed.
If Right(MyPath, 1) <> "\" Then
MyPath = MyPath & "\"
End If
' If there are no Excel files in the folder, exit.
FilesInPath = Dir(MyPath & "*.xlsx*")
If FilesInPath = "" Then
MsgBox "No files found"
Exit Sub
End If
' Fill in the myFiles array with the list of Excel files in
' the search folder.
FNum = 0
Do While FilesInPath <> ""
FNum = FNum + 1
ReDim Preserve MyFiles(1 To FNum)
MyFiles(FNum) = FilesInPath
FilesInPath = Dir()
Loop
' Change the application properties.
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
.EnableEvents = False
End With
' Add a new workbook with one sheet.
With Application
'--> Set contractor list file
Set listwb = .Workbooks.Open _
("D:\data\DataAssemble.xlsx")
End With
Set BaseWks = listwb.Sheets(1)
Cnum = 1
ActiveWorkbook.Sheets(1).Select
Range("P1").Select
ActiveCell.FormulaR1C1 = "Prod"
For Each mMonth In Sheets(1).Range("P1")
ActiveWorkbook.Sheets.Add after:=Worksheets(Worksheets.count)
ActiveSheet.Name = mMonth
Next
Set BaseWks = listwb.Sheets(7)
Cnum = 1
' Loop through all of the files in the myFiles array.
If FNum > 0 Then
For FNum = LBound(MyFiles) To UBound(MyFiles)
Set mybook = Nothing
On Error Resume Next
Set mybook = Workbooks.Open(MyPath & MyFiles(FNum))
On Error GoTo 0
If Not mybook Is Nothing Then
On Error Resume Next
Set sourceRange1 = mybook.Worksheets(1).Range("A1:B1420")
If Err.Number > 0 Then
Err.Clear
Set sourceRange1 = Nothing
Else
' If the source range uses all of the rows
' then skip this file.
If sourceRange1.Rows.count >= BaseWks.Rows.count Then
Set sourceRange1 = Nothing
End If
End If
On Error GoTo 0
If Not sourceRange1 Is Nothing Then
SourceCcount = sourceRange1.Columns.count
If Cnum + SourceCcount >= BaseWks.Columns.count Then
MsgBox "There are not enough columns in the sheet."
BaseWks.Columns.AutoFit
mybook.Close savechanges:=False
GoTo ExitTheSub
Else
' Copy the file name in the first row.
With sourceRange1
BaseWks.Cells(1, Cnum). _
Resize(, .Columns.count).Value = MyFiles(FNum)
End With
' Set the destination range.
Set destrange1 = BaseWks.Cells(1, Cnum)
' Copy the values from the source range
' to the destination range.
With sourceRange1
Set destrange1 = destrange1. _
Resize(.Rows.count, .Columns.count)
End With
destrange1.Value = sourceRange1.Value
Cnum = Cnum + SourceCcount
End If
End If
mybook.Close savechanges:=False
End If
BaseWks.Columns.AutoFit
Next FNum
End If
listwb.Activate
ActiveWorkbook.SaveAs Filename:="D:\data\Merged\19h\Data_ " & (FolderName) & ".xlsx",
Password:="", _
WriteResPassword:="", ReadOnlyRecommended:=False, CreateBackup:=False
ActiveWorkbook.Close
ExitTheSub:
'Restore ScreenUpdating, Calculation and EnableEvents
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = CalcMode
End With
End Sub
Thanks!
Sanjeev
I obtained this code from: http://vba-tutorial.com/merging-multiple-workbooks-togeather-by-searching-directories-and-sub-folders/
Step 1 - The recursive function
Sub RecursiveFileSearch(ByVal targetFolder As String, ByRef objRegExp As Object, _
ByRef matchedFiles As Collection, ByRef objFSO As Object)
Dim objFolder As Object
Dim objFile As Object
Dim objSubFolders As Object
'Get the folder object associated with the target directory
Set objFolder = objFSO.GetFolder(targetFolder)
'Loop through the files current folder
For Each objFile In objFolder.Files
If objRegExp.test(objFile) Then
matchedFiles.Add (objFile)
End If
Next
'Loop through the each of the sub folders recursively
Set objSubFolders = objFolder.Subfolders
For Each objSubfolder In objSubFolders
RecursiveFileSearch objSubfolder, objRegExp, matchedFiles, objFSO
Next
'Garbage Collection
Set objFolder = Nothing
Set objFile = Nothing
Set objSubFolders = Nothing
End Sub
Step 2 - Recursive controller
Function FindPatternMatchedFiles(sPath As String) As Collection
Dim objFSO As Object
Set objFSO = CreateObject("Scripting.FileSystemObject")
Dim objRegExp As Object
Set objRegExp = CreateObject("VBScript.RegExp")
objRegExp.Pattern = ".*\.(xls|xlsx)"
objRegExp.IgnoreCase = True
Dim colFiles As Collection
Set colFiles = New Collection
RecursiveFileSearch sPath, objRegExp, colFiles, objFSO
'Garbage Collection
Set objFSO = Nothing
Set objRegExp = Nothing
Set FindPatternMatchedFiles = colFiles
End Function
Step 3 - Merge together each of the matched Workbooks
Sub MergeWorkbooks(sPath As String, sWbName As String)
Dim colFiles As Collection
Set colFiles = FindPatternMatchedFiles(sPath)
Dim appExcel As New Excel.Application
appExcel.Visible = False
Dim wbDest As Excel.Workbook
Set wbDest = appExcel.Workbooks.Add()
Dim wbToAdd As Excel.Workbook
Dim sheet As Worksheet
For Each file In colFiles
Set wbToAdd = appExcel.Workbooks.Open(file)
For Each sheet In wbToAdd.Sheets
sheet.Copy Before:=wbDest.Sheets(wbDest.Sheets.Count)
Next sheet
wbToAdd.Close SaveChanges:=False
Next
wbDest.Close True, sPath + "\" + sWbName
Set wbDest = Nothing
Set appExcel = Nothing
End Sub
Step 4 - Call the Merge Workbooks sub routine
Sub Main()
MergeWorkbooks "C:\Path\To\Folder", "Awesomeness.xlsx"
End Sub
I'm trying to write an Excel Macro that will traverse through all the folders in the directory, and merge multiple excel spreadsheet into one. All the excel spreadsheet have the same format.
I'm able to traverse through all the folders in the directory but I keep getting errors when I try to merge the excel spreadsheet together.
This is the error message I got:
Run-time error '1004':
Excel cannot insert the sheets into the destination workbook, because
it contains fewer rows and columns than the source workbook. To move
or copy the data to the destination workbook, you can select the data,
and then use the Copy and Paste commands to insert it into the sheets
of another workbook.
This is what I have done so far:
Option Explicit
Sub FileListingAllFolder()
Dim pPath As String
Dim FlNm As Variant
Dim ListFNm As New Collection ' create a collection of filenames
Dim OWb As Workbook
Dim ShtCnt As Integer
Dim Sht As Integer
Dim MWb As Workbook
Dim MWs As Worksheet
Dim i As Integer
' Open folder selection
With Application.FileDialog(msoFileDialogFolderPicker)
.Title = "Select a Folder"
.AllowMultiSelect = False
If .Show <> -1 Then GoTo NextCode
pPath = .SelectedItems(1)
End With
Application.WindowState = xlMinimized
Application.ScreenUpdating = False
' Create master workbook with single sheets
Set MWb = Workbooks.Add(1)
MWb.Sheets(1).Name = "Result"
Set MWs = MWb.Sheets("Result")
' Filling a collection of filenames (search Excel files including subdirectories)
Call FlSrch(ListFNm, pPath, "*Issues.xls*", True)
' Print list to immediate debug window and as a message window
For Each FlNm In ListFNm ' cycle for list(collection) processing
'Start Processing here
Set OWb = Workbooks.Open(FlNm)
ShtCnt = ActiveWorkbook.Sheets.Count
For Sht = 1 To ShtCnt
Sheets(Sht).Copy After:=ThisWorkbook.Sheets(1)
Next Sht
OWb.Close False
Next FlNm
' Print to immediate debug window and message if no file was found
If ListFNm.Count = 0 Then
Debug.Print "No file was found !"
MsgBox "No file was found !"
MWb.Close False
End
End If
MWb.Activate
MWs.Activate
Cells.Select
Selection.EntireColumn.AutoFit
Range("A1").Select
Application.ScreenUpdating = True
Application.WindowState = xlMaximized
End
NextCode:
MsgBox "You Click Cancel, and no folder selected!"
End Sub
Private Sub FlSrch(pFnd As Collection, pPath As String, pMask As String, pSbDir As Boolean)
Dim flDir As String
Dim CldItm As Variant
Dim sCldItm As New Collection
' Add backslash at the end of path if not present
pPath = Trim(pPath)
If Right(pPath, 1) <> "\" Then pPath = pPath & "\"
' Searching files accordant with mask
flDir = Dir(pPath & pMask)
Do While flDir <> ""
pFnd.Add pPath & flDir 'add file name to list(collection)
flDir = Dir ' next file
Loop
' Procedure exiting if searching in subdirectories isn't enabled
If Not pSbDir Then Exit Sub
' Searching for subdirectories in path
flDir = Dir(pPath & "*", vbDirectory)
Do While flDir <> ""
' Do not search Scheduling folder
If flDir <> "Scheduling" Then
' Add subdirectory to local list(collection) of subdirectories in path
If flDir <> "." And flDir <> ".." Then If ((GetAttr(pPath & flDir) And _
vbDirectory) = 16) Then sCldItm.Add pPath & flDir
End If
flDir = Dir 'next file
Loop
' Subdirectories list(collection) processing
For Each CldItm In sCldItm
Call FlSrch(pFnd, CStr(CldItm), pMask, pSbDir) ' Recursive procedure call
Next
End Sub
I think this is the part that causes the problem.
For Each FlNm In ListFNm ' cycle for list(collection) processing
'Start Processing here
Set OWb = Workbooks.Open(FlNm)
ShtCnt = ActiveWorkbook.Sheets.Count
For Sht = 1 To ShtCnt
Sheets(Sht).Copy After:=ThisWorkbook.Sheets(1)
Next Sht
OWb.Close False
Next FlNm
I have been trying to mess with this code for two days now. I'm not too sure where I did it wrong. :(
If you have acess to vb.net I would urge you to use that in combination with Excel-Interop.
I have tried the same thing as you do know - basically, it never worked 100% satisfactory with pure VBA. The combination of Vb.net and interop worked like a charm.