Import multiple text/csv files into single excel worksheet - vba

I found this code to get the data from multiple csv/text files into an excel workbook. However, I would like the data to be appended to a single worksheet rather than each csv/text file having its own worksheet.
I have tried using Connection to get the data but when the file is being emailed to another user, there is an error prompt (Excel cannot find the text file to refresh this external data range) when he/she clicks on "Enable Content".
Sub CombineTextFiles()
Dim FilesToOpen
Dim x As Integer
Dim wkbAll As Workbook
Dim wkbTemp As Workbook
Dim sDelimiter As String
On Error GoTo ErrHandler
Application.ScreenUpdating = False
sDelimiter = "|"
FilesToOpen = Application.GetOpenFilename _
(FileFilter:="CSV Files (*.csv), *.csv", _
MultiSelect:=True, Title:="Text Files to Open")
If TypeName(FilesToOpen) = "Boolean" Then
MsgBox "No Files were selected"
GoTo ExitHandler
End If
x = 1
Set wkbTemp = Workbooks.Open(Filename:=FilesToOpen(x))
wkbTemp.Sheets(1).Copy
Set wkbAll = ActiveWorkbook
wkbTemp.Close (False)
wkbAll.Worksheets(x).Columns("A:A").TextToColumns _
Destination:=Range("A1"), DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, _
ConsecutiveDelimiter:=False, _
Tab:=False, Semicolon:=False, _
Comma:=False, Space:=False, _
Other:=True, OtherChar:="|"
x = x + 1
While x <= UBound(FilesToOpen)
Set wkbTemp = Workbooks.Open(Filename:=FilesToOpen(x))
With wkbAll
wkbTemp.Sheets(1).Move After:=.Sheets(.Sheets.Count)
.Worksheets(x).Columns("A:A").TextToColumns _
Destination:=Range("A1"), DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, _
ConsecutiveDelimiter:=False, _
Tab:=False, Semicolon:=False, _
Comma:=False, Space:=False, _
Other:=True, OtherChar:=sDelimiter
End With
x = x + 1
Wend
ExitHandler:
Application.ScreenUpdating = True
Set wkbAll = Nothing
Set wkbTemp = Nothing
Exit Sub
ErrHandler:
MsgBox Err.Description
Resume ExitHandler
End Sub

Consider using QueryTables that connect to your text files and wrap in a loop of your multiple selected csv files from the array, filesToOpen:
Sub ImportCSVFiles()
Dim filesToOpen As Variant, file As Variant, LastRow As Long, fso As Object
filesToOpen = Application.GetOpenFilename _
(FileFilter:="CSV Files (*.csv), *.csv", _
MultiSelect:=True, Title:="Text Files to Open")
For Each file In filesToOpen
LastRow = Cells(Rows.Count, 1).End(xlUp).Row
Set fso = CreateObject("Scripting.FileSystemObject")
fileName = fso.GetFilename(i)
If file = "False" Then Exit Sub
'IMPORT DATA FROM CSV FILES
With ActiveSheet.QueryTables.Add(Connection:="TEXT;" & file, _
Destination:=Cells(LastRow + 2, 1))
.TextFileStartRow = 30
.TextFileParseType = xlDelimited
.TextFileConsecutiveDelimiter = False
.TextFileTabDelimiter = False
.TextFileSemicolonDelimiter = False
.TextFileCommaDelimiter = True
.TextFileSpaceDelimiter = False
.Refresh BackgroundQuery:=False
End With
Next file
' REMOVING SOURCE CONNECTIONS
For Each qt In ActiveSheet.QueryTables
qt.Delete
Next qt
End Sub

I used this one to get the files. The downside is it gets to pull all data into this workbook.
Sub getallbooks()
Dim firstRowHeaders As Boolean
Dim fso As Object
Dim dir As Object
Dim filename As Variant
Dim wb As Workbook
Dim s As Sheet1
Dim thisSheet As Sheet1
Dim lastUsedRow As Range
Dim file As String
Dim fpath As String
On Error GoTo ErrMsg
Application.ScreenUpdating = False
firstRowHeaders = True 'Change from True to False if there are no headers in the first row
Set fso = CreateObject("Scripting.FileSystemObject")
'PLEASE NOTE: Change <<Full path to your Excel files folder>> to the path to the folder containing your Excel files to merge
fpath = Application.InputBox("Enter the file folder")
Set dir = fso.Getfolder(fpath)
Set thisSheet = ThisWorkbook.ActiveSheet
For Each filename In dir.Files
'Open the spreadsheet in ReadOnly mode
Set wb = Application.Workbooks.Open(filename, ReadOnly:=True)
'Copy the used range (i.e. cells with data) from the opened spreadsheet
If firstRowHeaders And i > 0 Then 'Only include headers from the first spreadsheet
Dim mr As Integer
mr = wb.ActiveSheet.UsedRange.Rows.Count
wb.ActiveSheet.UsedRange.Offset(1, 0).Resize(mr - 1).Copy
Else
wb.ActiveSheet.UsedRange.Copy
End If
'Paste after the last used cell in the master spreadsheet
If Application.Version < "12.0" Then 'Excel 2007 introduced more rows
Set lastUsedRow = thisSheet.Range("A65536").End(xlUp)
Else
Set lastUsedRow = thisSheet.Range("A1048576").End(xlUp)
End If
'Only offset by 1 if there are current rows with data in them
If thisSheet.UsedRange.Rows.Count > 1 Or Application.CountA(thisSheet.Rows(1)) Then
Set lastUsedRow = lastUsedRow.Offset(1, 0)
End If
lastUsedRow.PasteSpecial
Application.CutCopyMode = False
Next filename
ThisWorkbook.Save
Set wb = Nothing
#If Mac Then
'Do nothing. Closing workbooks fails on Mac for some reason
#Else
'Close the workbooks except this one
For Each filename In dir.Files
file = Right(filename, Len(filename) - InStrRev(filename, Application.PathSeparator, , 1))
Workbooks(file).Close SaveChanges:=False
Next filename
#End If
Application.ScreenUpdating = True
ErrMsg:
If Err.Number <> 0 Then
MsgBox "There was an error. Please try again. [" & Err.Description & "]"
End If
End Sub
Here is another way which creates a new workbook to store the data:
Sub MergeAllWorkbooks()
Dim MyPath As String, FilesInPath As String
Dim MyFiles() As String
Dim SourceRcount As Long, FNum As Long
Dim mybook As Workbook, BaseWks As Worksheet
Dim sourceRange As Range, destrange As Range
Dim rnum As Long, CalcMode As Long
Dim LastRow As Long, LastCol As Long
' Change this to the path\folder location of your files.
MyPath = InputBox("Enter the address here")
' Add a slash at the end of the 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 & "*.csv*") 'You can change the file type to suit your need here
If FilesInPath = "" Then
MsgBox "No files found"
Exit Sub
End If
' Fill 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
' Set various application properties.
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
.EnableEvents = False
End With
' Add a new workbook with one sheet.
Set BaseWks = Workbooks.Add(xlWBATWorksheet).Worksheets(1)
rnum = 1
' Loop through all 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
' Change this range to fit your own needs.
With mybook.Worksheets(1)
LastRow = .Cells(Rows.Count, 1).End(xlUp).Row 'choose which column has data all the way down the last row
LastCol = .Cells(1, Columns.Count).End(xlToLeft).Column
Set sourceRange = .Range(.Cells(1, 1), .Cells(LastRow, LastCol))
End With
If Err.Number > 0 Then
Err.Clear
Set sourceRange = Nothing
Else
' If source range uses all columns then
' skip this file.
If sourceRange.Columns.Count >= BaseWks.Columns.Count Then
Set sourceRange = Nothing
End If
End If
On Error GoTo 0
If Not sourceRange Is Nothing Then
SourceRcount = sourceRange.Rows.Count
If rnum + SourceRcount >= BaseWks.Rows.Count Then
MsgBox "There are not enough rows in the target worksheet."
BaseWks.Columns.AutoFit
mybook.Close savechanges:=False
GoTo ExitTheSub
Else
' Copy the file name in column A, if you want; Here I choose not.
' With sourceRange
' BaseWks.Cells(rnum, "A"). _
' Resize(.Rows.Count).Value = MyFiles(FNum)
' End With
' Set the destination range.
Set destrange = BaseWks.Range("A" & rnum)
' Copy the values from the source range
' to the destination range.
With sourceRange
Set destrange = destrange. _
Resize(.Rows.Count, .Columns.Count)
End With
destrange.Value = sourceRange.Value
rnum = rnum + SourceRcount
End If
End If
mybook.Close savechanges:=False
End If
Next FNum
BaseWks.Columns.AutoFit
End If
ExitTheSub:
' Restore the application properties.
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = CalcMode
End With
End Sub
Both of them get the header from each files. So You may want to remove them with only the top one left alone.

Thanks for the replies. Instead of using the code that i have shared above, I re-used connection which was my original code. To counter the connection error prompt (Excel cannot find the text file to refresh this external data range) when he/she clicks on "Enable Content", I added a code which removes all connections after the data is imported into the excel file. Hope this is helpful to someone who encountered the same issue as me. :)
Sub ImportMultipleCSV()
Dim myfiles
Dim i As Integer
myfiles = Application.GetOpenFilename(filefilter:="CSV Files (*.csv), *.csv", MultiSelect:=True)
If IsArray(myfiles) Then
For i = LBound(myfiles) To UBound(myfiles)
With ActiveSheet.QueryTables.Add(Connection:= _
"TEXT;" & myfiles(i), Destination:=Range("A" & Rows.Count).End(xlUp).Offset(1, 0))
.Name = "Sample"
.FieldNames = False
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.TextFilePromptOnRefresh = False
.TextFilePlatform = 437
.TextFileStartRow = 2
.TextFileParseType = xlDelimited
.TextFileTextQualifier = xlTextQualifierDoubleQuote
.TextFileConsecutiveDelimiter = True
.TextFileTabDelimiter = False
.TextFileSemicolonDelimiter = False
.TextFileCommaDelimiter = False
.TextFileSpaceDelimiter = False
.TextFileOtherDelimiter = "|"
.TextFileColumnDataTypes = Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
.TextFileTrailingMinusNumbers = True
.Refresh BackgroundQuery:=False
End With
Next i
Else
MsgBox "No File Selected"
End If
Dim xConnect As Object
For Each xConnect In ActiveWorkbook.Connections
If xConnect.Name <> "ThisWorkbookDataModel" Then xConnect.Delete
Next xConnect
End Sub

Related

VBA- Opening hyperlinks from a List to copy specific data into a master sheet

I currently am using the below code to generate a list of hyperlinks from a specific folder. I am trying to figure out how to access each of those hyperlinks to copy and paste certain data into a master spreadsheet then close the document in a loop. The data is located on the same tab for each file but In each file the number of Columns are always the same but not always the number of rows. Im trying to figure out how to capture all of that info into a master sheet without blanks and without overwriting data from the file before.
Option Compare Text
Option Explicit
Function Excludes(Ext As String) As Boolean
'Function purpose: To exclude listed file extensions from hyperlink listing
Dim x, NumPos As Long
'Enter/adjust file extensions to EXCLUDE from listing here:
x = Array("exe", "xlsm", "xml")
On Error Resume Next
NumPos = Application.WorksheetFunction.Match(Ext, x, 0)
If NumPos > 0 Then
Excludes = True
Else
Excludes = False
End If
On Error GoTo 0
End Function
Sub HyperlinkFileList()
'Macro purpose: To create a hyperlinked list of all files in a user
'specified directory, including file size and date last modified
'NOTE: The 'TextToDisplay' property (of the Hyperlink object) was added
'in Excel 2000. This code tests the Excel version and does not use the
'Texttodisplay property if using XL 97.
Dim fso As Object, _
ShellApp As Object, _
File As Object, _
SubFolder As Object, _
Directory As String, _
Problem As Boolean, _
ExcelVer As Integer, _
TotalD As String, _
Wb As Workbook, _
Ws As Worksheet
'Turn off screen flashing
Application.ScreenUpdating = False
' Clear sheet
Cells.Delete Shift:=xlUp
'Useless : Range("A1").Select
'Create objects to get a listing of all files in the directory
Set fso = CreateObject("Scripting.FileSystemObject")
'Prompt user to select a directory
Do
Problem = False
Set ShellApp = CreateObject("Shell.Application"). _
Browseforfolder(0, "Please choose a folder", 0, "D:\JBOSS\Testdossier")
'Browseforfolder(0, "Please choose a folder", 0, "D:\JBOSS\Testdossier")
On Error Resume Next
'Evaluate if directory is valid
Directory = ShellApp.self.Path
Set SubFolder = fso.GetFolder(Directory).Files
If Err.Number <> 0 Then
If MsgBox("You did not choose a valid directory!" & vbCrLf & _
"Would you like to try again?", vbYesNoCancel, _
"Directory Required") <> vbYes Then Exit Sub
Problem = True
End If
On Error GoTo 0
Loop Until Problem = False
'Set up the headers on the worksheet
With ActiveSheet
With .Range("A1")
.Value = "Listing of all files in:"
.ColumnWidth = 40
'If Excel 2000 or greater, add hyperlink with file name
'displayed. If earlier, add hyperlink with full path displayed
If Val(Application.Version) > 8 Then 'Using XL2000+
.Parent.Hyperlinks.Add _
Anchor:=.Offset(0, 1), _
Address:=Directory, _
TextToDisplay:=Directory
Else 'Using XL97
.Parent.Hyperlinks.Add _
Anchor:=.Offset(0, 1), _
Address:=Directory
End If
End With
With .Range("A2")
.Value = "File Name"
.Interior.ColorIndex = 15
.ColumnWidth = 50
With .Offset(0, 1)
.ColumnWidth = 15
.Value = "Date Modified"
.Interior.ColorIndex = 15
.HorizontalAlignment = xlCenter
End With
With .Offset(0, 2)
.ColumnWidth = 12
.Value = "File Size (Kb)"
.Interior.ColorIndex = 15
.HorizontalAlignment = xlCenter
End With
End With
End With
'Adds each file, details and hyperlinks to the list
For Each File In SubFolder
If Not Excludes(Right(File.Path, 3)) = True Then
With ActiveSheet
'If Excel 2000 or greater, add hyperlink with file name
'displayed. If earlier, add hyperlink with full path displayed
If Val(Application.Version) > 8 Then 'Using XL2000+
.Hyperlinks.Add _
Anchor:=ActiveSheet.Range("A65536").End(xlUp).Offset(1, 0), _
Address:=File.Path, _
TextToDisplay:=File.Name
Else 'Using XL97
.Hyperlinks.Add _
Anchor:=ActiveSheet.Range("A65536").End(xlUp).Offset(1, 0), _
Address:=File.Path
End If
'Add date last modified, and size in KB
With .Range("A65536").End(xlUp)
.Offset(0, 1) = File.datelastModified
With .Offset(0, 2)
.Value = WorksheetFunction.Round(File.Size / 1024, 1)
.NumberFormat = "#,##0.0"
End With
End With
'Add Total From this file to current workbook
Set Wb = Workbooks.Open(File)
Set Ws = Wb.Sheets("Summary")
On Error Resume Next
Wb.Close
Set Wb = Nothing
Set Ws = Nothing
End With
End If
Next File
'Turn back on screen updating
Application.ScreenUpdating = True
End Sub
Exactly! Why are you messing around with Hyperlinks? Just open a file, grab the data you need, close the file, and move on to the next one to do the same.
Sub Basic_Example_1()
Dim MyPath As String, FilesInPath As String
Dim MyFiles() As String
Dim SourceRcount As Long, Fnum As Long
Dim mybook As Workbook, BaseWks As Worksheet
Dim sourceRange As Range, destrange As Range
Dim rnum As Long, CalcMode As Long
'Fill in the path\folder where the files are
MyPath = "C:\Users\Ron\test"
'Add a slash at the end if the user forget it
If Right(MyPath, 1) <> "\" Then
MyPath = MyPath & "\"
End If
'If there are no Excel files in the folder exit the sub
FilesInPath = Dir(MyPath & "*.xl*")
If FilesInPath = "" Then
MsgBox "No files found"
Exit Sub
End If
'Fill the array(myFiles)with the list of Excel files in the folder
Fnum = 0
Do While FilesInPath <> ""
Fnum = Fnum + 1
ReDim Preserve MyFiles(1 To Fnum)
MyFiles(Fnum) = FilesInPath
FilesInPath = Dir()
Loop
'Change ScreenUpdating, Calculation and EnableEvents
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
.EnableEvents = False
End With
'Add a new workbook with one sheet
Set BaseWks = Workbooks.Add(xlWBATWorksheet).Worksheets(1)
rnum = 1
'Loop through all files in the array(myFiles)
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
With mybook.Worksheets(1)
Set sourceRange = .Range("A1:C1")
End With
If Err.Number > 0 Then
Err.Clear
Set sourceRange = Nothing
Else
'if SourceRange use all columns then skip this file
If sourceRange.Columns.Count >= BaseWks.Columns.Count Then
Set sourceRange = Nothing
End If
End If
On Error GoTo 0
If Not sourceRange Is Nothing Then
SourceRcount = sourceRange.Rows.Count
If rnum + SourceRcount >= BaseWks.Rows.Count Then
MsgBox "Sorry there are not enough rows in the sheet"
BaseWks.Columns.AutoFit
mybook.Close savechanges:=False
GoTo ExitTheSub
Else
'Copy the file name in column A
With sourceRange
BaseWks.cells(rnum, "A"). _
Resize(.Rows.Count).Value = MyFiles(Fnum)
End With
'Set the destrange
Set destrange = BaseWks.Range("B" & rnum)
'we copy the values from the sourceRange to the destrange
With sourceRange
Set destrange = destrange. _
Resize(.Rows.Count, .Columns.Count)
End With
destrange.Value = sourceRange.Value
rnum = rnum + SourceRcount
End If
End If
mybook.Close savechanges:=False
End If
Next Fnum
BaseWks.Columns.AutoFit
End If
ExitTheSub:
'Restore ScreenUpdating, Calculation and EnableEvents
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = CalcMode
End With
End Sub
https://www.rondebruin.nl/win/s3/win008.htm

Create separate row for each item when merging multiple workbooks

I have several hundred spreadsheets that I would like to combine into a single master sheet. Each spreadsheet contains general description information in several sells, and then a list of parts with columns of information that are specific to each part, as shown:
In the master sheet, I want a separate line for each part that includes the general information as well as the specific part information, as shown:
I have created a loop that pulls all the information I want, but all the information is written as a single line in the master sheet, as shown:
Can anyone tell me how to create a separate line for each item? The code I have pieced together is shown- I think the solution to my problem lies in how to format the section titled "change this range to fit your own needs"
Sub MergeNT154BatchCards()
Dim MyPath As String, FilesInPath As String
Dim MyFiles() As String
Dim SourceRcount As Long, FNum As Long
Dim mybook As Workbook, BaseWks As Worksheet
Dim dt As String
Dim bookName As String
Dim rnum As Long, CalcMode As Long
Dim a As Range, c As Range
Dim x As Long
Dim sourceRange As Range, destrange As Range
' Change this to the path\folder location of your files.
MyPath = "C:\Users\amiller\OneDrive - CoorsTek\temp"
' Add a slash at the end of the 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 & "*.xls*")
If FilesInPath = "" Then
MsgBox "No files found"
Exit Sub
End If
' Fill 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
' Set various application properties.
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
.EnableEvents = False
End With
' Add a new workbook with one sheet.
Set BaseWks = Workbooks.Add(xlWBATWorksheet).Worksheets(1)
ActiveSheet.Name = "Density"
bookName = "DensitySummary"
dt = Format(CStr(Now), "yyyy_mm_dd_hh.mm")
BaseWks.SaveAs Filename:="C:\Users\amiller\OneDrive - CoorsTek\temp\" & bookName & dt
rnum = 1
Range("A1").Value = "FileName"
Range("B1").Value = "Description"
Range("C1").Value = "WaterTemp(C)"
Range("D1").Value = "WaterDensity(g/cc)"
Range("E1").Value = "PartID"
Range("F1").Value = "DryMass(g)"
Range("G1").Value = "SuspendedMass(g)"
Range("H1").Value = "Density(g/cc)"
' Loop through all 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
' Change this range to fit your own needs.
With mybook.Worksheets(1)
Set R1 = Range("A11, A5, B5")
Set R2 = Range("A13:D" & Range("A13").End(xlDown).Row)
Set RF = Union(R1, R2)
Set sourceRange = RF
End With
If Err.Number > 0 Then
Err.Clear
Set sourceRange = Nothing
Else
' If source range uses all columns then
' skip this file.
If sourceRange.Columns.Count >= BaseWks.Columns.Count Then
Set sourceRange = Nothing
End If
End If
On Error GoTo 0
If Not sourceRange Is Nothing Then
SourceRcount = sourceRange.Rows.Count
If rnum + SourceRcount >= BaseWks.Rows.Count Then
MsgBox "There are not enough rows in the target worksheet."
BaseWks.Columns.AutoFit
mybook.Close savechanges:=False
GoTo ExitTheSub
Else
' Copy the file name in column A.
With sourceRange
BaseWks.Cells(rnum + 1, "A"). _
Resize(.Rows.Count).Value = MyFiles(FNum)
End With
' Set the destination range.
Set destrange = BaseWks.Range("B" & rnum + 1)
x = 0
For Each a In sourceRange.Areas
For Each c In a.Cells
x = x + 1
destrange.Offset(0, x - 1).Value = c.Value
Next c
Next a
' Copy the values from the source range
' to the destination range.
With sourceRange
Set destrange = destrange. _
Resize(.Rows.Count, .Columns.Count)
End With
destrange.Value = sourceRange.Value
rnum = rnum + SourceRcount
End If
End If
mybook.Close savechanges:=False
End If
Next FNum
BaseWks.Columns.AutoFit
End If
ExitTheSub:
' Restore the application properties.
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = CalcMode
End With
End Sub
I'm slightly worried because the headings you seem to be writing to the master sheet don't seem to line up with the data, and because you seem to be only copying Range("A11, A5, B5") from the top part of each sheet but your images show 5 fields being taken from the top, but I think you can replace your For FNum loop with the following:
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
With mybook.Worksheets(1)
Set SourceRange = .Range("A13:D" & .Range("A13").End(xlDown).Row)
SourceRcount = SourceRange.Rows.Count
If rnum + SourceRcount >= BaseWks.Rows.Count Then
MsgBox "There are not enough rows in the target worksheet."
BaseWks.Columns.AutoFit
mybook.Close savechanges:=False
GoTo ExitTheSub
Else
' Copy the file name in column A.
BaseWks.Cells(rnum + 1, "A").Resize(SourceRcount).Value = MyFiles(FNum)
' Copy information such as date/time started, start/final temp, and Batch ID
BaseWks.Cells(rnum + 1, "B").Resize(SourceRcount).Value = .Range("A4").Value
BaseWks.Cells(rnum + 1, "C").Resize(SourceRcount).Value = .Range("B4").Value
BaseWks.Cells(rnum + 1, "D").Resize(SourceRcount).Value = .Range("A5").Value
BaseWks.Cells(rnum + 1, "E").Resize(SourceRcount).Value = .Range("A5").Value
BaseWks.Cells(rnum + 1, "F").Resize(SourceRcount).Value = .Range("A11").Value
'Copy main data
BaseWks.Cells(rnum + 1, "G").Resize(SourceRcount, SourceRange.Columns.Count).Value = SourceRange.Value
rnum = rnum + SourceRcount
End If
End With
End If
mybook.Close savechanges:=False
Next FNum
The root of your problem is that you are trying to do too much in a single subroutine. Whenever your subroutines are over 25-40 lines, you should consider extracting functionality into smaller subroutines. In this way, you will be able to test smaller portions of code at a time.
By implementing this strategy, I managed to reduce the OPs original subroutine from 152 lines of code to 5 easy to debug subroutines with 80 lines of code.
MergeNT154BatchCards - Main subroutine
AddBatchCard - Opens a Workbook and adds new rows of data to a range
getDensityTemplate - Creates a new Workbook based off a template
getFileList - Gets a list of file from a directory
ToggleEvents - Turns off and on events and returns the current Calculation mode
I haven't tested some parts of the code and as #YowE3K stated the headers don't line up. I would think that it will be fairly easy to modify the code to fit the OPs requirement using these smaller blocks of code.
Public Sub MergeNT154BatchCards()
Dim vFiles As Variant, FileFullName As Variant
Dim NextRow As Range, wb As Workbook
Dim CalculationMode As XlCalculation
CalculationMode = ToggleEvents(False, xlCalculationManual)
vFiles = getFileList("C:\Users\best buy\Downloads\stackoverfow", "*.xls*")
If UBound(vFiles) = -1 Then
MsgBox "No files found", vbInformation, ""
Exit Sub
End If
Set wb = getDensityTemplate
For Each FileFullName In vFiles
With wb.Worksheets(1)
'Add Header
.Range("A1:H1").Value = Array("FileName", "Description", "WaterTemp(C)", "WaterDensity(g/cc)", "PartID", "DryMass(g)", "SuspendedMass(g)", "Density(g/cc)")
'Target the next empty row
Set NextRow = .Range("A" & .Rows.Count).End(xlUp).Offset(1)
AddBatchCard CStr(FileFullName), NextRow
End With
Next
ToggleEvents True, CalculationMode
End Sub
Private Sub AddBatchCard(FileFullName As String, NextRow As Range)
Dim cell As Range
Dim x As Long, y As Long
With Workbooks.Open(FileFullName)
With .Worksheets(1)
For Each cell In .Range("A13", .Range("A" & .Rows.Count).End(xlUp)).Value
'NextRow
NextRow.Cells(1, 1).Value = .Range("A4").Value
NextRow.Cells(1, 2).Value = .Range("B4").Value
NextRow.Cells(1, 3).Value = .Range("A5").Value
NextRow.Cells(1, 4).Value = .Range("B5").Value
NextRow.Cells(1, 4).Resize(1, 4).Value = cell.Resize(1, 4).Value
Set NextRow = NextRow.Offset(1)
Next
End With
.Close SaveChanges:=False
End With
End Sub
Private Function getDensityTemplate(FilePath As String) As Workbook
Dim SheetsInNewWorkbook As Integer
Dim wb As Workbook
SheetsInNewWorkbook = Application.SheetsInNewWorkbook
Application.SheetsInNewWorkbook = 1
Set wb = Workbooks.Add(xlWBATWorksheet)
wb.Worksheets(1).Name = "Density"
wb.SaveAs FileName:=FilePath & "DensitySummary" & Format(Now, "yyyy_mm_dd_hh.mm")
Set getDensityTemplate = wb
End Function
Private Function getFileList(FilePath As String, PatternSearch As String) As Variant
Dim FileName As String
If Right(FilePath, 1) <> "\" Then FilePath = FilePath & "\"
With CreateObject("System.Collections.ArrayList")
FileName = Dir(FilePath & PatternSearch)
Do While FileName <> ""
.Add FilePath & FileName
FileName = Dir()
Loop
getFileList = .ToArray
End With
End Function
Private Function ToggleEvents(EnabelEvents As Boolean, CalculationMode As XlCalculation) As XlCalculation
With Application
ToggleEvents = .Calculation
.Calculation = CalculationMode
.ScreenUpdating = EnabelEvents
.EnableEvents = EnabelEvents
End With
End Function

How to copy multiple files in a folder into a single spreadsheet?

I just started using excel macros. My problem is that I have 500 excel files in a folder. I am looking for a way to copy the first and second column of each of these 500 files into a single spreadsheet. Is this something that can be done using the excel VBA. Any help is appreciated. Please see the VBA code I recorded. How can I modify this to achieve my objective?
Sub Macro1()
'
' Macro1 Macro
'
'
ActiveCell.Range("A1:B1").Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Copy
Windows("Book1").Activate
ActiveSheet.Paste
End Sub
Please read my comments within the code.
You have to correct your path(addresses), folder names and file names.
Option Explicit
Sub LoopAllFiles()
Dim myCalc As XlCalculation
Application.EnableCancelKey = xlDisabled
Application.ScreenUpdating = False
Application.Calculation = myCalc
Application.Calculation = xlCalculationManual
Dim folderPath As String
Dim Filename As String
Dim wb As Workbook, wbMaster As Workbook
Dim sh As Worksheet
Dim ColNo As Long
ColNo = 1
folderPath = "C:\testfolder\" 'contains folder path
'or folderPath = "C:\Users\AshleyLarson\Desktop\LoopThroughFolders\AnyFolder\"
' ==> Please correct your path otherwise code won't work. <==
If Right(folderPath, 1) <> "\" Then folderPath = folderPath + "\"
Filename = Dir(folderPath & "*.xlsx")
Do While Filename <> ""
Set wb = Workbooks.Open(folderPath & Filename)
Set wbMaster = Workbooks.Open(folderPath & "masterfolder\Master Template.xlsx") ' BE CAREFUL This should be your Master File's path
wb.Sheets(1).Range("A1:B" & (Range("A" & Rows.Count).End(xlUp).Row) + 100).Copy
Workbooks("Master Template").Worksheets("Sheet1").Range(Chr(ColNo + 64) & ":" & Chr((ColNo + 1) + 64)).PasteSpecial xlPasteValues
ColNo = ColNo + 2
Application.DisplayAlerts = False
Workbooks(Filename).Save
Workbooks(Filename).Close
Workbooks("Master Template.xlsx").Save
Workbooks("Master Template.xlsx").Close
Application.DisplayAlerts = True
Filename = Dir
Loop
Application.ScreenUpdating = True
Application.Calculation = myCalc
End Sub
This can be done in Power Query with just a few clicks on ribbon icons. No VBA required.
Start a new query
from file
navigate to folder
select all files
remove files you don't need with filters (optional step)
combine binaries
select the columns you want to keep
If the files in the folder change, just refresh the query.
Power Query is a free add-in from Microsoft for Excel 2010 and 2013 and built into Excel 2016 as Get & Transform.
Try it this way.
Sub Basic_Example_1()
Dim MyPath As String, FilesInPath As String
Dim MyFiles() As String
Dim SourceRcount As Long, Fnum As Long
Dim mybook As Workbook, BaseWks As Worksheet
Dim sourceRange As Range, destrange As Range
Dim rnum As Long, CalcMode As Long
'Fill in the path\folder where the files are
MyPath = "C:\Users\Ron\test"
'Add a slash at the end if the user forget it
If Right(MyPath, 1) <> "\" Then
MyPath = MyPath & "\"
End If
'If there are no Excel files in the folder exit the sub
FilesInPath = Dir(MyPath & "*.xl*")
If FilesInPath = "" Then
MsgBox "No files found"
Exit Sub
End If
'Fill the array(myFiles)with the list of Excel files in the folder
Fnum = 0
Do While FilesInPath <> ""
Fnum = Fnum + 1
ReDim Preserve MyFiles(1 To Fnum)
MyFiles(Fnum) = FilesInPath
FilesInPath = Dir()
Loop
'Change ScreenUpdating, Calculation and EnableEvents
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
.EnableEvents = False
End With
'Add a new workbook with one sheet
Set BaseWks = Workbooks.Add(xlWBATWorksheet).Worksheets(1)
rnum = 1
'Loop through all files in the array(myFiles)
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
With mybook.Worksheets(1)
Set sourceRange = .Range("A1:C1")
End With
If Err.Number > 0 Then
Err.Clear
Set sourceRange = Nothing
Else
'if SourceRange use all columns then skip this file
If sourceRange.Columns.Count >= BaseWks.Columns.Count Then
Set sourceRange = Nothing
End If
End If
On Error GoTo 0
If Not sourceRange Is Nothing Then
SourceRcount = sourceRange.Rows.Count
If rnum + SourceRcount >= BaseWks.Rows.Count Then
MsgBox "Sorry there are not enough rows in the sheet"
BaseWks.Columns.AutoFit
mybook.Close savechanges:=False
GoTo ExitTheSub
Else
'Copy the file name in column A
With sourceRange
BaseWks.cells(rnum, "A"). _
Resize(.Rows.Count).Value = MyFiles(Fnum)
End With
'Set the destrange
Set destrange = BaseWks.Range("B" & rnum)
'we copy the values from the sourceRange to the destrange
With sourceRange
Set destrange = destrange. _
Resize(.Rows.Count, .Columns.Count)
End With
destrange.Value = sourceRange.Value
rnum = rnum + SourceRcount
End If
End If
mybook.Close savechanges:=False
End If
Next Fnum
BaseWks.Columns.AutoFit
End If
ExitTheSub:
'Restore ScreenUpdating, Calculation and EnableEvents
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = CalcMode
End With
End Sub
https://www.rondebruin.nl/win/s3/win008.htm

Excel VBA; copying specific worksheets from multiple workbooks in different locations

I can copy a sheet named "Alpha" from 6 separate workbooks in the one directory, but I'm not sure how to get the code to loop around to pick up sheets in other files & locations with slightly different names.
I thought I could use :
IF sheetname LIKE "Alpha" then
sheetToCopy = make this the name of the sheet I want to copy
END IF
It doesn't pass the name of the sheet onto the variable though. I think it's because I'm already looping through an array, using file names & numbers.
The code below works perfectly for the 6 Alpha sheets, but it won't pick up "Y Alpha" or "Alpha XZ".
Any help would be very much appreciated!
I use the following code:
Sub AlphaTest()
Dim MyPath As String
Dim SourceRcount As Long, FNum As Long
Dim mybook As Workbook, BaseWks As Worksheet
Dim sourceRange As Range, destrange As Range
Dim rnum As Long, CalcMode As Long
Dim SaveDriveDir As String
Dim FName As Variant
Dim FirstCell As String
Dim sName As String
' Set application properties.
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
.EnableEvents = False
End With
SaveDriveDir = CurDir
' Change this to the path\folder location of the files.
ChDirNet "Z:\"
FName = Application.GetOpenFilename(filefilter:="Excel Files (*.xl*), *.xl*", _
MultiSelect:=True)
If IsArray(FName) Then
' Add a new workbook with one sheet.
Set BaseWks = Workbooks.Add(xlWBATWorksheet).Worksheets(1)
rnum = 1
' Loop through all files in the myFiles array.
For FNum = LBound(FName) To UBound(FName)
Set mybook = Nothing
On Error Resume Next
Set mybook = Workbooks.Open(FName(FNum), ReadOnly:=True)
On Error GoTo 0
If Not mybook Is Nothing Then
On Error Resume Next
'If ActiveWorkbook.Worksheets.Name Like "*Debtors*" Then
' sName = ActiveWorkbook.Worksheets.Name
'Else
' sName = "0"
'End If
With mybook.Worksheets("Alpha")
FirstCell = "A6"
Set sourceRange = .Range(FirstCell & ":" & RDB_Last(3, .Cells))
' Test if the row of the last cell is equal to or greater than the row of the first cell.
If RDB_Last(1, .Cells) < .Range(FirstCell).Row Then
Set sourceRange = Nothing
End If
End With
If Err.Number > 0 Then
Err.Clear
Set sourceRange = Nothing
Else
' If the source range uses all columns then
' skip this file.
If sourceRange.Columns.Count >= BaseWks.Columns.Count Then
Set sourceRange = Nothing
End If
End If
On Error GoTo 0
If Not sourceRange Is Nothing Then
SourceRcount = sourceRange.Rows.Count
If rnum + SourceRcount >= BaseWks.Rows.Count Then
MsgBox "There are not enough rows in the target worksheet."
BaseWks.Columns.AutoFit
mybook.Close savechanges:=False
GoTo ExitTheSub
Else
' Copy the file name in column A.
With sourceRange
BaseWks.Cells(rnum, "A"). _
Resize(.Rows.Count).Value = FName(FNum)
End With
' Set the destination range.
Set destrange = BaseWks.Range("C" & rnum)
' Copy the values from the source range
' to the destination range.
With sourceRange
Set destrange = destrange. _
Resize(.Rows.Count, .Columns.Count)
End With
destrange.Value = sourceRange.Value
rnum = rnum + SourceRcount + 1
End If
End If
mybook.Close savechanges:=False
End If
Next FNum
BaseWks.Columns.AutoFit
End If
ExitTheSub:
' Restore the application properties.
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = CalcMode
End With
ChDirNet SaveDriveDir
End Sub
From what I can see, you simply want to keep reopening the GetOpenFile dialog until the user cancels out (i.e. doesn't want to bring anymore files in).
Option Explicit
Sub AlphaTest()
Dim FName As Variant
'bunch of code here
FName = Application.GetOpenFilename(filefilter:="Excel Files (*.xl*), *.xl*", _
MultiSelect:=True)
Do While FName <> "False"
If IsArray(FName) Then
'lots of code here
End If
FName = Application.GetOpenFilename(filefilter:="Excel Files (*.xl*), *.xl*", _
MultiSelect:=True)
Loop
ExitTheSub:
'bunch of code here
End Sub

Consolidate Excel Files into Master File (VBA)

Could someone please take a look at my code and tell me what Iā€™m doing wrong? I'm trying to consolidate a group of excel files that are in a folder into a master Excel file. My logic seems right but for some reason, the data is not pasting into the master file from the source files. Thank you all in advance!
Sub ConsolidateMAR()
'
'
'
Dim lastRow As Long
Dim MyFolder As String
Dim myFile As String
Dim wbkSource As Workbook
Dim wkbDest As Workbook
Set wkbDest = Workbooks.Open("C:\Users\xxxxx\Desktop\MAR Test Master File.xlsx")
On Error Resume Next
Application.ScreenUpdating = False
With Application.FileDialog(msoFileDialogFolderPicker)
.Title = "Please select a folder"
.Show
.AllowMultiSelect = False
If .SelectedItems.Count = 0 Then 'If no folder is selected, abort
MsgBox "You did not select a folder"
Exit Sub
End If
MyFolder = .SelectedItems(1) & "\" 'Assign selected folder to MyFolder
End With
myFile = Dir(MyFolder) 'DIR gets the first file of the folder
'Loop through all files in a folder until DIR cannot find anymore
Do While myFile <> ā€œā€
'Opens the file and assigns to the wbkSource variable for future use
Set wbkSource = Workbooks.Open(FileName:=MyFolder & myFile)
'Replace the line below with the statements you would want your macro to perform
If Err.Number <> 0 Then
MsgBox ("Unable to open file " & myFile)
End If
On Error GoTo 0
wbkSource.ActiveSheet.Unprotect Password:="adgiam"
Columns.EntireColumn.Hidden = False
Rows.EntireRow.Hidden = False
Rows("3:3").Select
Selection.AutoFilter
Rows("3:3").Select
Selection.AutoFilter
lastRow = wbkSource.ActiveSheet.Cells(Rows.Count, "B").End(xlUp).Row
Range("A4:W" & lastRow).Select
Selection.Copy
Application.DisplayAlerts = False
erow = wkbDest.Sheets(1).Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
wkbDest.ActiveSheet.Paste Destination:=Sheets(1).Range(Cells(erow, 1), Cells(erow, 23))
wbkSource.Close SaveChanges:=False
myFile = Dir 'DIR gets the next file in the folder
Loop
wkbDest.Close SaveChanges:=True
Application.ScreenUpdating = True
MsgBox "Macro has completed! Woot! Woot!"
End Sub
I had to do something similar, but chose to move the sheets into the new workbook.
See So, I have 6 "master" files to then divide into 40 separate files
Those select statements are pretty dangerous. Try to avoid those and just make a direct reference to the object you want to control.
Something like this should work for you.
Sub Basic_Example_1()
Dim MyPath As String, FilesInPath As String
Dim MyFiles() As String
Dim SourceRcount As Long, Fnum As Long
Dim mybook As Workbook, BaseWks As Worksheet
Dim sourceRange As Range, destrange As Range
Dim rnum As Long, CalcMode As Long
'Fill in the path\folder where the files are
MyPath = "C:\Users\Ron\test"
'Add a slash at the end if the user forget it
If Right(MyPath, 1) <> "\" Then
MyPath = MyPath & "\"
End If
'If there are no Excel files in the folder exit the sub
FilesInPath = Dir(MyPath & "*.xl*")
If FilesInPath = "" Then
MsgBox "No files found"
Exit Sub
End If
'Fill the array(myFiles)with the list of Excel files in the folder
Fnum = 0
Do While FilesInPath <> ""
Fnum = Fnum + 1
ReDim Preserve MyFiles(1 To Fnum)
MyFiles(Fnum) = FilesInPath
FilesInPath = Dir()
Loop
'Change ScreenUpdating, Calculation and EnableEvents
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
.EnableEvents = False
End With
'Add a new workbook with one sheet
Set BaseWks = Workbooks.Add(xlWBATWorksheet).Worksheets(1)
rnum = 1
'Loop through all files in the array(myFiles)
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
With mybook.Worksheets(1)
Set sourceRange = .Range("A1:C1")
End With
If Err.Number > 0 Then
Err.Clear
Set sourceRange = Nothing
Else
'if SourceRange use all columns then skip this file
If sourceRange.Columns.Count >= BaseWks.Columns.Count Then
Set sourceRange = Nothing
End If
End If
On Error GoTo 0
If Not sourceRange Is Nothing Then
SourceRcount = sourceRange.Rows.Count
If rnum + SourceRcount >= BaseWks.Rows.Count Then
MsgBox "Sorry there are not enough rows in the sheet"
BaseWks.Columns.AutoFit
mybook.Close savechanges:=False
GoTo ExitTheSub
Else
'Copy the file name in column A
With sourceRange
BaseWks.cells(rnum, "A"). _
Resize(.Rows.Count).Value = MyFiles(Fnum)
End With
'Set the destrange
Set destrange = BaseWks.Range("B" & rnum)
'we copy the values from the sourceRange to the destrange
With sourceRange
Set destrange = destrange. _
Resize(.Rows.Count, .Columns.Count)
End With
destrange.Value = sourceRange.Value
rnum = rnum + SourceRcount
End If
End If
mybook.Close savechanges:=False
End If
Next Fnum
BaseWks.Columns.AutoFit
End If
ExitTheSub:
'Restore ScreenUpdating, Calculation and EnableEvents
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = CalcMode
End With
End Sub
Also, check out the AddIn below.
http://www.rondebruin.nl/win/addins/rdbmerge.htm