Excel VB for importing data from folders - vba

I am working on a project in excel that requires importing data from files on network.
The issue I am facing is as follows:
I have a folder (in shared drive) in which there are few sub-folders and an excel file in the end sub-folder. The excel file has many tabs out of which I have to import the data from only 1 particular tab (e.g. Summary). This process has to be repeated for all the files in all the sub-folders.
Here is the flow diagram of the description.
Folder A -> Sub-folder1 -> Sub-folder2 -> {Excel file1, Excel file2}
Now, what I am looking for is, that whenever I add a new excel file in the sub-folder 2, the data from that same tab (Summary) of the excel file (all excel files have same tabs with different data) should be imported to my destination excel file and make a graph of the data. I need a VB script to run this functionality.
Also, if I have more sub-folders, then will VB take longer time to run ?
I tried the following but doesn't seem to work:
Sub ConFiles()
Dim Wbname As String
Dim Wb As Workbook
Dim ws As Worksheet
Dim ws1 As Worksheet
Dim lngCalc As Long
Dim lngrow As Long
With Application
.ScreenUpdating = False
.EnableEvents = False
lngCalc = .CalculationState
.Calculation = xlCalculationManual
End With
Set ws1 = ThisWorkbook.Sheets.Add
'change folder path here
FolderName = "C:\temp"
Wbname = Dir(FolderName & "\" & "*.xls*")
'ThisWorkbook.Sheets(1).UsedRange.ClearContents
Do While Len(Wbname) > 0
Set Wb = Workbooks.Open(FolderName & "\" & Wbname)
Set ws = Nothing
On Error Resume Next
'change sheet name here
Set ws = Wb.Sheets("loging form")
On Error GoTo 0
If Not ws Is Nothing Then
lngrow = lngrow + 1
ws.Rows(2).Copy ws1.Cells(lngrow, "A")
End If
Wb.Close False
Wbname = Dir
Loop
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = lngCalc
End With
End Sub

Function GetExcelFiles(ByVal strFilePath As String) As String()
Dim arrStr As String() = Nothing
If Directory.Exists(strFilePath) Then
arrStr = GetFilePath(strFilePath)
Else
'error message here
End If
Return arrStr
End Function
Private Function GetFilePath(ByVal strFilePath As String) As String()
Dim arrFileNames As String() = Directory.GetFiles(strFilePath, "*.xls", SearchOption.AllDirectories)
Return arrFileNames
End Function
The code above is how to get all excel files. Next thing is... open the workbook and read per worksheet. To read file by file, you can loop using For Each.
For Each strFileName In arrStr
'your code here
Next
where strFileName = GetExcelFiles(folderPath)
Don't forget to add Imports Microsoft.Office.Interop.Excel
then
Dim excel As New Application
Dim workbook As Workbook = excel.Workbooks.Open(strFileName)
Now you have the workbook. To read per sheet, do it this way and put it in a function that returns boolean.
Dim worksheet As Worksheet
For intIndex As Integer = 1 To workbook.Sheets.Count
worksheet = workbook.Sheets(intIndex)
If worksheet.Name.Equals(THE_SHEETNAME) Then
'returns true
Exit For
End If
Next
Now you can proceed with your process.

Related

Excel VBA Copy a Workbook to another one with Dialog

I am a beginner in Excel VBA programming and am tasked to develop a Tool in Excel for monitoring. I do have knowledge in other Languages like Java, C++ and Python, therefore I know how to do the Logic, but VBA is a difficult one.
The Thing:
What I need to get working is the following:
I have a Workbook, lets call it Tool.xlsm in which I've wrote the sorting and filtering logic. This part is working fine. It uses a seperate sheet in that workbook for the "background data". This sheet is what this is about.
I want to write a macro which displays a file selection dialouge. The selected file then gets copied to a new sheet in my Workbook. The file is a .xls table with 3 sheets. The data needed is in sheet 1.
Public Sub copyData()
Set appxl = CreateObject("Excel.application")
Dim myfile As Window
Dim currentSheet As Worksheet
Dim lastRow As Double
Dim sourceFileName As String
sourceFileName = "FileToCopy.xlsx"
'Open Source File.xlsx
With appxl
.Workbooks.Open ActiveWorkbook.Path & "\" & sourceFileName
.Visible = False
End With
'Get first sheet data
Set myfile = appxl.Windows(sourceFileName)
myfile.Activate
Set currentSheet = appxl.Sheets(1)
'Past the table in my current Excel file
lastRow = currentSheet.Range("A1").End(xlDown).Row
Sheets("Data retrieval").Range("A1:Y" & lastRow) = currentSheet.Range("A1:Y"& lastRow).Value
'Close Source File.xlsx
appxl.Workbooks(sourceFileName).Close
End Sub
This is the Code I wrote with the help of the famous GoogleSearch.
Now to the Specific Questions:
How do I code a FileSelectionDialouge?
how do I fix the error 9, outofBounds?
Ive searched in Stackoverflow for quite some time, but didnt find a similar problem.
This is my first Post here, I apologize for any mistakes made.
Also I apologize for any grammar or vocabular mistakes, english is not my native language :)
Many thanks for reading.
Ninsa
Edit: Ive modified the code according to the answers below. It now looks like this:
Public Sub copyData2()
Set appxl = CreateObject("Excel.application")
Dim myfile As Window
Dim currentSheet As Worksheet
Dim lastRow As Double
Dim sourceFileName As String
'Ask the user to select a file
With Application.FileDialog(msoFileDialogFilePicker)
.AllowMultiSelect = False
.ButtonName = "Import File"
.InitialView = msoFileDialogViewSmallIcons
.Title = "Please Select File"
If .Show = -1 Then Collation_File = .SelectedItems(1)
End With
sourceFileName = Collation_File
'Open Source File.xlsx
With appxl
.Workbooks.Open Collation_File
.Visible = False
End With
'Get first sheet data
Set myfile = appxl.Windows(sourceFileName)
myfile.Activate
Set currentSheet = Workbooks("sourceFileName").Sheets(1)
'Past the table in my current Excel file
lastRow = currentSheet.Range("A1").End(xlDown).Row
Debug.Print lastRow
Sheets("test").Range("A1:Y" & lastRow) = currentSheet.Range("A1:Y" & lastRow).Value
'Close Source File.xlsx
appxl.Workbooks(sourceFileName).Close
End Sub
For the first part you could use the following function based on this article in MSDN
Function GetFileName() As String
GetFileName = ""
' Open the file dialog
With Application.FileDialog(msoFileDialogOpen)
.AllowMultiSelect = False
If .Show = -1 Then
GetFileName = .SelectedItems(1)
End If
End With
End Function
Update I re-wrote your code to
Public Sub copyData()
Dim sourceWkb As Workbook
Dim sourceWks As Worksheet
Dim targetWks As Worksheet
Dim sourceFilename As String
Dim lastRow As Long
Set targetWks = Sheets("Data retrieval")
sourceFilename = GetFileName
Set sourceWkb = Workbooks.Open(sourceFilename)
Set sourceWks = sourceWkb.Sheets(1)
'Past the table in my current Excel file
lastRow = sourceWks.Range("A1").End(xlDown).Row
targetWks.Range("A1:Y" & lastRow) = sourceWks.Range("A1:Y" & lastRow).Value
'Close Source File.xlsx
sourceWkb.Close False
End Sub
With Application.ScreenUpdating = Falseyou can turn off screen flickering.

File loop is wrongfully skipping files

I have written the below code to loop through all the files in a directory and copy certain values from them and paste it back into the master file.
The problem that I am having is that the code never fully runs through all the files and I never get an error.
As shown in the picture the file names are depicted as 1 - #####, then 2 - ####, etc.
Sometimes there are multiple of the first number like in the picture there are two 1 - ###'s but the end numbers are still different.
The problem is that instead of going by the actual numerical order the code is using only the first number and going from 1, 10, 11, 100 and completely skipping the rest.
Any ideas on how to solve this?
Sub ReadDataFromCloseFile()
On Error GoTo ErrHandler
Application.EnableEvents = False
Application.ScreenUpdating = False
Dim FileType As String
Dim FilePath As String
FileType = "*.xlsm*" 'The file type to search for
FilePath = "\\filepath\" 'The folder to search
Dim src As Workbook
Dim OutputCol As Variant
Dim Curr_File As Variant
OutputCol = 9 'The first row of the active sheet to start writing to
Curr_File = Dir(FilePath & FileType)
Do Until Curr_File = ""
' OPEN THE SOURCE EXCEL WORKBOOK IN "READ ONLY MODE".
Set src = Workbooks.Open(FilePath & Curr_File, True, True)
Sheets("Reporting").Range("I7:I750").Copy
Workbooks("Master.xlsm").Activate
Sheets("Sheet2").Select
Sheets("Sheet2").Cells(4, OutputCol).Select
ActiveCell.PasteSpecial Paste:=xlPasteValuesAndNumberFormats
Application.CutCopyMode = False
OutputCol = OutputCol + 1
' CLOSE THE SOURCE FILE.
src.Close False ' FALSE - DON'T SAVE THE SOURCE FILE.
Curr_File = Dir
Loop
Set src = Nothing
Application.EnableEvents = True
Application.ScreenUpdating = True
ErrHandler:
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
Filepath
I've no idea why it doesn't open the 2 to 9 files. This version puts all the file paths into a collection and then steps through the collection.
It also does away with selecting the sheets before pasting, etc.
Sub ReadDataFromCloseFile()
Dim FileType As String
Dim FilePath As String
Dim colFiles As Collection
Dim src As Workbook
Dim tgt As Workbook
Dim OutputCol As Variant
Dim Curr_File As Variant
Set colFiles = New Collection
FileType = "*.xlsm*" 'The file type to search for
FilePath = "\\filepath\" 'The folder to search
EnumerateFiles FilePath, FileType, colFiles
OutputCol = 9 'The first row of the active sheet to start writing to
'If Master.xlsm is the book containing this code then use '=ThisWorkbook'
Set tgt = Workbooks("Master.xlsm")
For Each Curr_File In colFiles
Set src = Workbooks.Open(Curr_File, True, True)
src.Worksheets("Reporting").Range("I7:I750").Copy
tgt.Worksheets("Sheet2").Cells(4, OutputCol).PasteSpecial xlPasteValuesAndNumberFormats
OutputCol = OutputCol + 1
src.Close False
Next Curr_File
End Sub
Sub EnumerateFiles(ByVal sDirectory As String, _
ByVal sFileSpec As String, _
ByRef cCollection As Collection)
Dim sTemp As String
sTemp = Dir$(sDirectory & sFileSpec)
Do While Len(sTemp) > 0
cCollection.Add sDirectory & sTemp
sTemp = Dir$
Loop
End Sub
It might be easier for you to loop through the files using the below loop.
Sub LoopFiles()
Dim FSO As New FileSystemObject
Dim Fldr As Folder
Dim Fl As File
'Loop through files in folder
For Each Fl In FSO.GetFolder(filePath).Files
'Check for file type
If Fl.Type = "Excel Macro-Enabled Workbook" Then
'Open file & do procedure
End If
Next
Set FSO = Nothing
End Sub
Try declaring your variable OutputCol as an integer and not a variant. If you know your data is always going to be a number, it's never a good idea to use a variant. It takes more resources to execute the code and you don't know all of the internal logic that is going on behind the scenes. It also gives you more control of the code's execution and probably won't give you headaches like this one. Only use a variant if you don't know what data you are going to output.
Hope this helps!

copy information to an external workbook

I am writing a macro where I take data from a CSV and copy it to another Excel file (not the current or active file).
What is the code to take the copied data and send it to another file in the same directory.
This is my code, I have commented out the lines that cause the macro not to work. I want to set the variable wshT to Sheet1 of the WTF.xlsx file, which is in the same directory but not the active workbook. I have not opened that one. So the goal is to use this macro to copy extra data from the CSV and send it to the WTF.xlsx file and save it as something new, in this case "BBB". Any help is much appreciated. When I uncomment those lines, errors pop up.
Sub Import()
Dim MyPath As String
Dim strFileName As String
'Dim strFileName1 As String
MyPath = ActiveWorkbook.Path
strFileName = MyPath & "\borgwich_die_BM1940_profile.csv"
'strFileName1 = Workbooks("WTF.xlsx").Activate
'strFileName1 = Workbooks("WTF.xlsx").Worksheets("Sheet1").Select
Dim wbkS As Workbook
Dim wshS As Worksheet
Dim wshT As Worksheet
'Set wshT = strFileName1
Set wbkS = Workbooks.Open(Filename:=strFileName)
Set wshS = wbkS.Worksheets(1)
wshS.Range("A1:A3").EntireRow.Delete
'wshS.UsedRange.Copy Destination:=wshT.Range("A1")
wbkS.Close SaveChanges:=False
Application.DisplayAlerts = False
ActiveWorkbook.SaveAs Filename:=MyPath & "\BBB", FileFormat _
:=51, CreateBackup:=False
Application.DisplayAlerts = False
'ActiveWindow.Close
End Sub
Your use of value assignment to strFileName1 through the use of .Activate and/or .Select was bad methodology. If WTF.xlsx is open, you can directly reference its Sheet1 and Set a worksheet object reference to a variable.
Sub Import()
Dim MyPath As String, strFileName As String
Dim wbkS As Workbook, wshS As Worksheet, wshT As Worksheet
MyPath = ActiveWorkbook.Path
strFileName = MyPath & "\borgwich_die_BM1940_profile.csv"
Set wbkS = Workbooks.Open(Filename:=strFileName)
Set wshS = wbkS.Worksheets(1)
Set wshT = Workbooks("WTF.xlsx").Worksheets("Sheet1")
wshS.Range("A1:A3").EntireRow.Delete
With wshS.Cells(1, 1).CurrentRegion
.Copy Destination:=wshT.Range("A1")
End With
wbkS.Close SaveChanges:=False
Application.DisplayAlerts = False
wshT.Parent.SaveAs Filename:=MyPath & "\BBB", FileFormat:=51, CreateBackup:=False
wshT.Parent.Close SaveChanges:=False
Application.DisplayAlerts = True
End Sub
Another alternative would be to use the VBA equivalent of Data ► Get External Data ► From Text but you should probably know the number and type of fields being brought in with the CSV beforehand. This is certainly the preferred method if the CSV data is being incorrectly interpreted by the temp worksheet you are creating by opening the CSV as a workbook.

Merging workbooks into a master workbook with seperate sheet for each file

I have 30 xlsx files in a folder and I want the first sheet of all that files to be merged to a new workbook. The thing is I don't want the macro to copy paste the value in to the same sheet of the new master sheet like Ron's excel merge tool does. I want a macro to create new 30 sheets on the master file and copy the data from source files. And I want the newly added sheets to be renamed as the source file name. I searched the forums for hours and found the below code. This works well except the sheet renaming thing. Can someone please look into the code and please help me to add sheet rename part to the code?
Sub Merge2MultiSheets()
Dim wbDst As Workbook
Dim wbSrc As Workbook
Dim wsSrc As Worksheet
Dim MyPath As String
Dim strFileName As String
Application.DisplayAlerts = False
Application.EnableEvents = False
Application.ScreenUpdating = False
MyPath = "C:\Jude" ' change to suit
Set wbDst = Workbooks.Add(xlWBATWorksheet)
strFileName = Dir(MyPath & "\*.xlsx", vbNormal)
If Len(strFileName) = 0 Then Exit Sub
Do Until strFileName = ""
Set wbSrc = Workbooks.Open(Filename:=MyPath & "\" & strFileName)
Set wsSrc = wbSrc.Worksheets(1)
wsSrc.Copy After:=wbDst.Worksheets(wbDst.Worksheets.Count)
wbSrc.Close False
strFileName = Dir()
Loop
wbDst.Worksheets(1).Delete
Application.DisplayAlerts = True
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
wsSrc.Copy After:=wbDst.Worksheets(wbDst.Worksheets.Count)
wbDst.Worksheets(wbDst.Worksheets.Count).Name = strFileName
If you want to include the path then you'll need to remove the backslash '\' and any other invalid sheet-name characters.
Make sure the name does not contain any of the following characters: :
\ / ? * [ or ]

Browsing Main excel file and Save As directory path with use of Excel VBA

I have below Excel procedure I gather up and I am using it for couple of different calculations under different workbooks. So I was thinking instead changing the procedure for main and outcome files each time, I should be able to pick the file I want to carry out calculations in and the file path for outcomes files.
But I could not find anything for saving directory, I appreciate if you could help
Sub AsBuiltForm()
Dim SaveName As String
Dim mainBook As Workbook
a = InputBox("ENTER FIRST NUMBER ")
b = InputBox("ENTER LAST NUMBER ")
Workbooks.Open Filename:="C:\" 'main file can be browsed?
Set mainBook = Excel.Workbooks("CP.xlsx")
For i = a - 1 To b - 1
mainBook.Sheets(1).Range("bi1") = i + 1
SaveName = Sheets(1).Range("bi1").value & ".xlsx"
mainBook.SaveCopyAs "C:\" & SaveName 'save directory?
Workbooks.Open Filename:="C:\" & SaveName 'save directory?
With Excel.ActiveWorkbook
.Sheets("1 of 2").Range("A1:CT103").value = Sheets("1 of 2").Range("A1:CT103").value
.Sheets("2 of 2").Range("A1:CT103").value = Sheets("2 of 2").Range("A1:CT103").value
Excel.Application.DisplayAlerts = False
.Sheets("Sheet1").Delete
.Sheets("il oufall").Delete
.Sheets("1 of 2").Select
Columns("Bh:BZ").Select
Selection.Delete Shift:=xlToLeft
.Sheets("2 of 2").Select
Columns("Bn:BZ").Select
Selection.Delete Shift:=xlToLeft
.Close True
End With
Next
mainBook.Close False
Set mainBook = Nothing
End Sub
You can use Application.GetOpenFileName to pick files that you want to open at Run-Time.
You can use the function below to browse for a folder where you wish to save a file.
Sub FindFolder()
Dim myFolder as String
myFolder = BrowseFolder("Pick a Folder Where to Save")
End Sub
Function BrowseFolder(Optional Caption As String, Optional InitialFolder As String) As String
' based on Browse For Folder from:
' http://www.cpearson.com/excel/BrowseFolder.aspx
' this functions requires that the following Reference is active:
'Microsoft Shell Controls and Automation
Const BIF_RETURNONLYFSDIRS As Long = &H1
Dim wsh As Object
Dim SH As Shell32.Shell
Dim F As Shell32.Folder
Set wsh = CreateObject("Wscript.Shell")
Set SH = New Shell32.Shell
Set F = SH.BrowseForFolder(0&, Caption, BIF_RETURNONLYFSDIRS, InitialFolder)
If Not F Is Nothing Then
If F = "Desktop" Then
BrowseFolder = wsh.Specialfolders(F)
Else
BrowseFolder = F.Items.Item.path
End If
End If
End Function
The following is not really an answer to your question, but a few tips to improve your code, and too long to add as a comment.
Workbooks.Open returns a Workbook object you can save the reference, so you don't have to rely on ActiveWorkbook:
Dim oWorkbook As Workbook
Set oWorkbook = Workbooks.Open(Filename:="C:\" & SaveName)
'***** Do something with oWorkbook
Debug.Print oWorkbook.FullName
Set oWorkbook = Nothing
A few other hints:
Use Option Explicit at the top of every module to force explicit declaration of all variables in order to find typos and other errors earlier.
Avoid selecting cells
Yes, browsing file works now; all the ins and outs aside, the problem i face with naming the file due to the variable "bi1" and saving as many loop as i asked for. I check several times before i bother you but i do not think i have the sufficient info to address "fn" as file in the use of Application.GetOpenFileName .
Option Explicit
Sub AsBuiltForm()
Dim fn
Dim myFolder As String
Dim SaveName As String, a As Integer, b As Integer, i As Integer
myFolder = BrowseFolder("Pick a Folder Where to Save")
MsgBox "Choose Calculation File "
fn = Application.GetOpenFilename
Workbooks.Open fn
a = InputBox("ENTER FIRST NUMBER ")
b = InputBox("ENTER LAST NUMBER ")
For i = a - 1 To b - 1 Step 1
Application.DisplayAlerts = False
Workbooks.Open Filename:=fn
Range("bi1") = i + 1
SaveName = ActiveWorkbook.Sheets(1).Range("bi1").value
Sheets(1).Range("A1:CT103").value = Sheets(1).Range("A1:CT103").value
Sheets(2).Range("A1:CT103").value = Sheets(2).Range("A1:CT103").value
Application.ActiveWorkbook.SaveAs myFolder & SaveName
ActiveWorkbook.Close True
Next
End Sub
Function BrowseFolder(Optional Caption As String, Optional InitialFolder As String) As String
' based on Browse For Folder from:
' http://www.cpearson.com/excel/BrowseFolder.aspx
' this functions requires that the following Reference is active:
'Microsoft Shell Controls and Automation
Const BIF_RETURNONLYFSDIRS As Long = &H1
Dim wsh As Object
Dim SH As Shell32.Shell
Dim F As Shell32.Folder
Set wsh = CreateObject("Wscript.Shell")
Set SH = New Shell32.Shell
Set F = SH.BrowseForFolder(0&, Caption, BIF_RETURNONLYFSDIRS, InitialFolder)
If Not F Is Nothing Then
If F = "Desktop" Then
BrowseFolder = wsh.Specialfolders(F)
Else
BrowseFolder = F.Items.Item.Path
End If
End If
End Function