I'm trying to code a Macro in Excel that:
Goes through hundreds of .csv files.
Get their names and put them in the first row of the target workbook.
Copy columns E & R from each .csv file and paste them below their corresponding name in the target workbook.
Example: in the target workbook, I should get, the title_1 (of csv_1) in cell A1, then data from columns E & R of csv_1 pasted in cells A2 & B2. Column C empty. Then title_2 (of csv_2) in cell D1, respective columns E & R pasted in D2 & E2. Column F empty and so on...
I would like the data to be organize like this
Attempt:
Sub LoopExcels ()
Dim directory As String
Dim fileName As String
Dim i As Integer
Dim j As Integer
Dim wb As Workbook
Dim wbSource As Workbook
Dim wsSource As Worksheet
Dim wsTarget As Worksheet
Dim ColOutputTarget As Long
ColOutputTarget = 1
Set wsTarget = Sheets("Sheet1")
Application.ScreenUpdating = FALSE
Application.DisplayAlerts = FALSE
directory = "C:\data"
fileName = Dir(directory & "*.csv")
Do Until fileName = ""
Set wbSource = Workbooks.Open(directory & fileName)
Set wsSource = wbSource.Worksheets(1)
j = j + 1
i = 1
Cells(i, 1) = fileName
Workbooks.Open (directory & fileName)
For Each sheet In Workbooks(fileName).Worksheets 'my excels contain only one sheet but didn't know how to get rid of the "For each sheet"
wsTarget.Cells(i, j).Value = sheet.Name
j = j + 2
Next sheet
With wsTarget
.Range("A" & ColOutputTarget).Value = wsSource.Range("E1:E100").Value 'Need to copy all data in columns it can be 10 cells and it doesn't exceed 100 cells
.Range("B" & ColOutputTarget).Value = wsSource.Range("R1:R100").Value
ColOutputTarget = ColOutputTarget + 1
End With
wbSource.Close SaveChanges:=False
fileName = Dir()
Loop
Application.CutCopyMode = FALSE
End Sub
I've been looking for a solution with no luck.
I found a way to loop through files
I managed partially to get the names of each file (I found a code that goes thru all sheets in an Excel file. My files contain only one sheet so maybe it can be simplified)
And for some reason it doesn't copy the full name. some files have LONG names +50 characters.
I am having issues with copy/pasting the columns. Each column has data from 10 to 100 cells.
The code below, go thru the files but paste the data in the same column. I end up getting only the data from the last excel file it opens which get pasted in the first 2 columns.
I can't find a way to make it shift to the next column every time its done with each csv file.
For order to work:
you need to place the Excel file (that has the macro) inside the folder of the .CSV files.
create 2 sheets in the main Excel file with the names "file names" and "target sheet". You can change this in the code if you want.
if you are using Windows just insert the path of the folder containing the .csv files.
if you are using mac insert the path of the folder containing the .csv files and change all the "\" in the macro to "/".
Sub Awesome()
getNames
positionTitles
transferData
End Sub
Sub getNames()
Dim sFilePath As String
Dim sFileName As String
Dim counter As Long
counter = 1
'Specify folder Path for the .csv files
sFilePath = "c:\"
'Check for back slash
If Right(sFilePath, 1) <> "\" Then
sFilePath = sFilePath & "\"
End If
sFileName = Dir(sFilePath & "*.csv")
Do While Len(sFileName) > 0
If Right(sFileName, 3) = "csv" Then
'Display file name in immediate window
Sheets("file names").Cells(counter, 1) = sFileName
counter = counter + 1
End If
'Set the fileName to the next available file
sFileName = Dir
Loop
End Sub
Sub positionTitles()
Dim counter As Long
Dim used_range As Range
Dim col As Long
col = 1
Set used_range = Sheets("file names").UsedRange
For counter = 1 To used_range.Rows.Count
Sheets("target sheet").Cells(1, col) = Sheets("file names").Cells(counter, 1)
col = col + 4
Next counter
End Sub
Sub transferData()
'turn off unnecessary applications
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Application.EnableEvents = False
Application.DisplayAlerts = False
Dim file_name As String
Dim counter As Long
Dim used_range As Range
Dim main_wb As Workbook
Dim col As Long
Dim key As Boolean
Dim last_row As Long
Dim second_key As Boolean
col = 1
Set main_wb = ThisWorkbook
Set used_range = Sheets("file names").UsedRange
For counter = 1 To used_range.Rows.Count
file_name = main_wb.Sheets("file names").Cells(counter, 1)
Workbooks.Open ActiveWorkbook.Path & "\" & file_name, Local:=True
'transfer data to target_sheet
For col = col To 1000
If key = False Then
last_row = ActiveWorkbook.ActiveSheet.Range("E" & Rows.Count).End(xlUp).Row
ActiveWorkbook.ActiveSheet.Range("E1:E" & last_row).Copy
main_wb.Sheets("target sheet").Cells(2, col).PasteSpecial
key = True
ElseIf second_key = False Then
last_row = ActiveWorkbook.ActiveSheet.Range("R" & Rows.Count).End(xlUp).Row
ActiveWorkbook.ActiveSheet.Range("R1:R" & last_row).Copy
main_wb.Sheets("target sheet").Cells(2, col).PasteSpecial
second_key = True
Else
last_row = ActiveWorkbook.ActiveSheet.Range("K" & Rows.Count).End(xlUp).Row
ActiveWorkbook.ActiveSheet.Range("K1:K" & last_row).Copy
main_wb.Sheets("target sheet").Cells(2, col).PasteSpecial
col = col + 2
Exit For
End If
Next col
key = False
second_key = False
Workbooks(file_name).Close savechanges:=False
Next counter
'turn on applications
Application.ScreenUpdating = True
Application.Calculation = xlCalculationManual
Application.EnableEvents = True
Application.DisplayAlerts = True
Application.DisplayAlerts = True
End Sub
Related
Loop in folder is work, but don't work loop cells, don't work copy and paste selected data from 50 Excel workbooks to a single destination Excel workbook. I work in Windows Operating System. I have folder with 50 Excel files. I have single destiny Excel file. Data go from folder to 1 single Excel file.
Help, please.
Sub Combine()
Dim s As String, MyFiles As String
Dim endd As Integer, startt As Integer
Dim NewWb As Workbook
Dim newS As Worksheet
Dim i As Long
Application.DisplayAlerts = False
Application.ScreenUpdating = False
Set NewWb = Workbooks.Add
With NewWb
Set newS = NewWb.Worksheets("Лист1")
End With
endd = i * 10 + 1
startt = endd - 10
MyFiles = "C:\Users\User\Desktop\Nezavisimai\Papka2\"
s = Dir(MyFiles & "*.xlsx")
Do While s <> ""
[a1] = 0
If Dir = "" Then Exit Sub Else i = 1
Do
If Dir = "" Then Exit Do Else i = i + 1
Loop Until False
[a1] = i
With Workbooks.Open(MyFiles & s)
.Worksheets("Данные").Range("A1:C10").Copy
.Close SaveChanges:=False
End With
newS.Select
With newS
.Range("B" & startt & ":D" & endd).Paste
End With
s = Dir
Loop
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
Option Explicit
Sub Combine()
Const FOLDER = "C:\Users\User\Desktop\Nezavisimai\Papka2\"
Dim wb As Workbook, wbNew As Workbook, wsNew As Worksheet
Dim filename As String, i As Long, n As Integer, rng As Range
Set wbNew = Workbooks.Add(xlWBATWorksheet) '1 sheet
Set wsNew = wbNew.Sheets(1)
Application.ScreenUpdating = False
i = 1
filename = Dir(FOLDER & "*.xlsx")
Do While filename <> ""
' open book and copy range
Set wb = Workbooks.Open(FOLDER & filename, False, True) ' no link update, read only
Set rng = wb.Sheets(1).Range("A1:C10")
rng.Copy wsNew.Range("B" & i)
i = i + rng.Rows.Count
' close book goto next
wb.Close False
n = n + 1
filename = Dir
Loop
' save combined
wbNew.SaveAs ThisWorkbook.Path & "\Combined.xlsx"
wbNew.Close False
Application.ScreenUpdating = True
MsgBox n & " files copied", vbInformation
End Sub
I've frankensteined some code together which does the following:
Deletes first few rows in a worksheet if they're not the header names
Deletes columns with specific names
Does this for all worksheets in a specified folder
I need help updating the code to do the following:
If the first row already contains the headers, then it will just move to the next step
Keeps columns with specific names, delete the rest
Do this for all sheets within a worksheet, if there happen to be multiple ones
Thank you so much in advance for any help!
Option Explicit
Sub test()
Dim wkb As Workbook
Dim MyPath As String
Dim MyFile As String
Application.ScreenUpdating = False
Set wkb = ActiveWorkbook
MyPath = "C:\Users\Katerina Shapiro\Desktop\VBA" 'Change this based on your folder path'
If Right(MyPath, 1) <> "\" Then MyPath = MyPath & "\"
MyFile = Dir(MyPath & "*.xlsx")
Do While Len(MyFile) > 0
If MyFile <> wkb.Name Then
Workbooks.Open Filename:=MyPath & MyFile
Dim rng As Range
Set rng = Range("B1:B4") 'Change this if there are more rows to be deleted before the header'
rng.SpecialCells(xlCellTypeBlanks).EntireRow.Delete
Dim xFNum, xFFNum, xCount As Integer
Dim xStr As String
Dim xArrName As Variant
Dim MR, xRg As Range
On Error Resume Next
Set MR = Range("A1:H1")
xArrName = Array("Placement (detail) url", "Placement (group)") 'enclose each column name with double quotes and separate them by comma
xCount = MR.Count
xStr = xArrName(xFNum)
For xFFNum = xCount To 1 Step -1
Set xRg = Cells(1, xFFNum)
For xFNum = 0 To UBound(xArrName)
xStr = xArrName(xFNum)
If xRg.Value = xStr Then xRg.EntireColumn.Delete
Next xFNum
Next
ActiveWorkbook.Close SaveChanges:=True
End If
MyFile = Dir
Loop
Application.ScreenUpdating = True
MsgBox "Completed...", vbInformation
End Sub
Should get you close:
Option Explicit
Sub test()
Dim wkb As Workbook, wbMod As Workbook, ws As Worksheet
Dim MyPath As String
Dim MyFile As String, h, keepCols, col As Long, i As Long
Application.ScreenUpdating = False
Set wkb = ActiveWorkbook 'ThisWorkbook ?
MyPath = "C:\Users\Katerina Shapiro\Desktop\VBA" 'Change this based on your folder path'
If Right(MyPath, 1) <> "\" Then MyPath = MyPath & "\"
keepCols = Array("Placement (detail) url", "Placement (group)") 'columns to keep
MyFile = Dir(MyPath & "*.xlsx")
Do While Len(MyFile) > 0
If MyFile <> wkb.Name Then
Set wbMod = Workbooks.Open(Filename:=MyPath & MyFile) 'get reference to opened file
For Each ws In wbMod.Worksheets 'loop over worksheets
'remove any empty rows at the top of the sheet
i = 0
Do While Application.CountA(ws.Rows(1)) = 0
ws.Rows(1).Delete
i = i + 1
If i >= 5 Then Exit Do 'don't keep deleting forever...
Loop
'loop column headers in Row 1 right to left: delete column if header not in "keep" array
For col = ws.Cells(1, Columns.Count).End(xlToRight).Column To 1 Step -1
If IsError(Application.Match(ws.Cells(1, col).Value, keepCols, 0)) Then
ws.Columns(col).Delete
End If
Next col
Next ws
wbMod.Close True 'save changes
End If
MyFile = Dir()
Loop
Application.ScreenUpdating = True
MsgBox "Completed...", vbInformation
End Sub
For i = 1 To 2 'This for loop deletes all rows on top of the workbook where the cell in column B is empty
If Cells(i, 2).Value = "" Then
Rows(i).Delete
i = i - 1
End If
Next
This one should solve your first problem.
WS_Count = ActiveWorkbook.Worksheets.Count
For i = 1 To WS_Count
...
Next i
If you implement this loop it looks how many sheets there are in the workbook and loop through it.
For i=1 to Cells(7, sht.Columns.Count).End(xlToLeft).Column
If Cells(1,i).Value="" Then 'You need to insertthe Names of the columns you want to keep here.
columns(i).delete
i=i-1
endif
Next
And this should solve the columns delete problem.
So I want to automate a lot of manual work of copy/paste with the help of a Macro. The macro should read all files from folder one by one, copy the content from that source file range "I9:J172" and paste it on the destination file (where the macro is of course) on the column first blank row.
Application.ScreenUpdating = False
'For Each Item In franquicia
' OPEN THE SOURCE EXCEL WORKBOOK IN "READ ONLY MODE".
Set src = Workbooks.Open("C:\folder\inventory.xlsb", True, True)
' GET THE TOTAL ROWS FROM THE SOURCE WORKBOOK.
Dim iTotalRows As Integer
iTotalRows = src.Worksheets("INV").Range("I9:J" & Cells(Rows.Count, "J").End(xlUp).Row).Rows.Count
' FIND FIRST BLANK CELL
Dim LastRow As Long
LastRow = Worksheets("Hoja1").Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
' COPY DATA FROM SOURCE (CLOSE WORKGROUP) TO THE DESTINATION WORKBOOK.
Dim iCnt As Integer ' COUNTER.
For iCnt = 1 To iTotalRows
Worksheets("Hoja1").Range("A" & LastRow & ":B" & iCnt).Value = src.Worksheets("INV").Range("I9:J172" & iCnt).Value
Next iCnt
' CLOSE THE SOURCE FILE.
src.Close False ' FALSE - DON'T SAVE THE SOURCE FILE.
Set src = Nothing
'Next Item
I want to solve first this last row problem and then do an array and the loop to read all the files one by one.
Thank you!
The following code does what you've described, and the animated gif demonstrates with 3 test files (with test data in the columns you mentioned). The first part of the gif shows the contents of 2 of the test files, and then runs the macro, stepping through it, showing the result on a "combined" sheet. Click on the gif to see better detail. Note that each test file's data must be on a "data" sheet. You can modify, of course.
Option Explicit
Dim theDir As String, alreadyThere As Boolean, wk As Workbook
Dim sh As Worksheet, comboSh As Worksheet, comboR As Range
Dim r As Range, s As String, numFiles As Integer
Const ext = ".xlsx"
Sub CombineFiles()
Set comboSh = getSheet(ThisWorkbook, "Combined", True)
theDir = ThisWorkbook.Path
s = Dir(theDir & "\*" & ext)
Set comboR = comboSh.Range("A1")
While s <> ""
ThisWorkbook.Activate
If comboR <> "" Then Set comboR = comboR.Offset(0, 2)
comboR.Activate
Set wk = Workbooks.Open(theDir & "\" & s)
Set sh = getSheet(wk, "data", False)
Set r = sh.Range("I9:J72")
'Set r = sh.Range(r, r.End(xlToRight))
'Set r = sh.Range(r, r.End(xlDown))
r.Copy
comboSh.Paste
Application.DisplayAlerts = False
wk.Close False
Application.DisplayAlerts = True
s = Dir()
numFiles = numFiles + 1
Wend
MsgBox ("done")
End Sub
Function getSheet(wk As Workbook, shName As String, makeIfAbsent As Boolean) As Worksheet
alreadyThere = False
For Each sh In wk.Worksheets
If sh.Name = shName Then
alreadyThere = True
Set getSheet = sh
End If
Next
If Not alreadyThere Then
If makeIfAbsent Then
Set getSheet = wk.Sheets.Add
getSheet.Name = shName
Else
MsgBox shName & " sheet not found -- ending"
End
End If
End If
End Function
I may be arriving to the party too late. It seems like you got the solution you were after. For future reference, try the AddIn below. This will do all kinds of copy/paste/merge tasks.
https://www.rondebruin.nl/win/addins/rdbmerge.htm
I'm trying to get a spreadsheet that will import data from another file, scan the file for certain values in column D and then paste specific cells (not the whole row) into the first row that has a blank cell in column F in the new spreadsheet.
This is my updated code now
Sub GetAmazonData()
Dim counter As Integer
Dim LastRow As Long
Dim Adspend As Workbook
Dim A As String
Dim Amazon As Workbook
Dim sourceSheet As Worksheet
Dim targetSheet As Worksheet
Set Adspend = ActiveWorkbook
Application.ScreenUpdating = False
Application.DisplayAlerts = False
'Specify data export file
A = Application.GetOpenFilename(Title:="Select File To Be Processed")
Set Amazon = Application.Workbooks.Open(A)
counter = 2
' While Not Amazon.Worksheets(1).Range("D" & counter) = ""
If Amazon.Worksheets(1).Range("D" & counter) = "B01GB3HZ34" Then
Set targetSheet = Adspend.Worksheets("DirtyDom")
Set sourceSheet = Amazon.Worksheets(1)
LastRow = Adspend.Worksheets("DirtyDom").Cells(Adspend.Worksheets("DirtyDom").Rows.Count, "F").End(xlUp).Row
targetSheet.Range("F" & LastRow).Value = sourceSheet.Range("D" & counter).Value
Else
LastRow = Adspend.Worksheets("DirtyDom").Cells(Adspend.Worksheets("DirtyDom").Rows.Count, "F").End(xlUp).Row
targetSheet.Range("F" & LastRow).Value = sourceSheet.Range("D4").Value
End If
' ActiveCell.Offset(1, 0).Active
' Wend
Amazon.Close
End Sub
I expect this bit of code to paste what is in the imported file's first sheet cell D1 into the sheet called DirtyDom in cell F1 since 1 is the first cell blank in column F.
I get the error Object variable or With block variable not set.
Thank you!
Try something like this, it also puts your loop back in and resets your screen updating and alerts - untested.
Sub GetAmazonData()
Dim Adspend As Workbook
Dim Amazon As Workbook
Dim Targetsheet As Worksheet
Dim Amazonsheet As Worksheet
Dim Amazonfilename As String
Dim lastAmazonrow As Long
Dim lastTargetrow As Long
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Set Adspend = ActiveWorkbook
Set Targetsheet = Adspend.Worksheets("DirtyDom")
'Specify data export file
Amazonfilename = Application.GetOpenFilename(Title:="Select File To Be Processed")
Set Amazon = Application.Workbooks.Open(Amazonfilename)
Set Amazonsheet = Amazon.Worksheets(1)
lastAmazonrow = Amazonsheet.Cells(Amazonsheet.Rows.Count, "D").End(xlUp).Row
lastTargetrow = Targetsheet.Cells(Targetsheet.Rows.Count, "F").End(xlUp).Row + 1
For counter = 1 To lastAmazonrow
If Amazonsheet.Range("D" & counter) = "B01GB3HZ34" Then
Targetsheet.Range("F" & lastTargetrow).Value = Amazonsheet.Range("D" & counter).Value
Else
Targetsheet.Range("F" & lastTargetrow).Value = Amazonsheet.Range("D4").Value
End If
lastTargetrow = lastTargetrow + 1
Next i
Amazon.Close
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub
I have some csv files in one folder. They all contain 3 specific columns. The number of total columns and the order may vary.
I want to concatenate all 3 columns with an underscore and write them in a single column in the worksheet that is running the code.
Here is what I have so far:
Option Explicit
Sub test()
Dim i As Long
Dim LastRow As Long
Dim Columns()
Columns = Array("Column1", "Column2", "Column3")
'Find Columns by Name
For i = 0 To 2
Columns(i) = Rows(1).Find(What:=Columns(i), LookIn:=xlValues, LookAt:=xlWhole, _
MatchCase:=False, SearchFormat:=False).Column
Next i
'Debug.Print Columns(0)
'Debug.Print Columns(1)
'Debug.Print Columns(2)
LastRow = Cells(Rows.Count, "A").End(xlUp).Row
For i = 2 To LastRow
Cells(i, 1) = Cells(i, Columns(0)) & "_" & Cells(i, Columns(1)) & "_" & Cells(i, Columns(2))
Next i
End Sub
As you can see, this does what I want, but only for the active sheet.
I actually want to loop through all csv files in the same folder as the active sheet and write the results in the first sheet, first column of the sheet running the code (which is not a csv itself obviously).
How can I do this?
thanks!
This is a code that will loop through a folder
Sub Button1_Click()
Dim MyFile As String, Str As String, MyDir As String, Wb As Workbook
Set Wb = ThisWorkbook
'change the address to suite
MyDir = "C:\WorkBookLoop\"
MyFile = Dir(MyDir & "*.xls") 'change file extension
ChDir MyDir
Application.ScreenUpdating = 0
Application.DisplayAlerts = 0
Do While MyFile <> ""
Workbooks.Open (MyFile)
'do something here
MyFile = Dir()
Loop
End Sub
It depends how you are naming the worksheets you create from the CSV files. You could add all the worksheets to a collection and use a For...Each loop to execute the entire search and concatenate procedure within that loop. Note that you'd have to explicitly define the first sheet name as this won't change through successive loops:
Option Explicit
Sub test()
Dim i As Long
Dim LastRow As Long
Dim Columns()
Dim frontSheet as Worksheet
Dim wSheets as New Collection
Dim ws as Worksheet
Set frontSheet = Sheets("name of front sheet")
'Add all your CSV sheets to wSheets using the .Add() method.
For Each ws in wSheets
Columns = Array("Column1", "Column2", "Column3")
'Find Columns by Name
For i = 0 To 2
Columns(i) = ws.Rows(1).Find(What:=Columns(i), LookIn:=xlValues, LookAt:=xlWhole, _
MatchCase:=False, SearchFormat:=False).Column
Next i
'Debug.Print Columns(0)
'Debug.Print Columns(1)
'Debug.Print Columns(2)
LastRow = ws.Cells(Rows.Count, "A").End(xlUp).Row
For i = 2 To LastRow
frontsheet.Cells(i, 1) = ws.Cells(i, Columns(0)) & "_" & ws.Cells(i, Columns(1)) & "_" & ws.Cells(i, Columns(2))
Next i
Next ws
End Sub
It's often slow and labourious to open CSV files in excel but VBA can read them as text files using a TextStream. Furthermore, file scripting objects let you work with files and directories directly. Something like this might be a better approach if you don't need to keep the files in a worksheet afterwards:
Sub SearchFoldersForCSV()
Dim fso As Object
Dim fld As Object
Dim file As Object
Dim ts As Object
Dim strPath As String
Dim lineNumber As Integer
Dim lineArray() As String
Dim cols() As Integer
Dim i As Integer
Dim frontSheet As Worksheet
Dim frontSheetRow As Integer
Dim concatString As String
Set frontSheet = Sheets("name of front sheet")
frontSheetRow = 1
strPath = "C:\where-im-searching\"
Set fso = CreateObject("Scripting.FileSystemObject")
Set fld = fso.GetFolder(strPath)
For Each file In fld.Files
If (Right(file.Name, 3) = "csv") Then
Debug.Print file.Name
Set ts = file.OpenAsTextStream()
lineNumber = 0
Do While Not ts.AtEndOfStream
lineNumber = lineNumber + 1
lineArray = Split(ts.ReadLine, ",")
If (lineNumber = 1) Then
'We are at the first line of the .CSV so
'find index in lineArray of columns of interest
'Add extra ElseIf as required
For i = LBound(lineArray) To UBound(lineArray)
If lineArray(i) = "Column 1" Then
cols(1) = i
ElseIf lineArray(i) = "Column 2" Then
cols(2) = i
ElseIf lineArray(i) = "Column 3" Then
cols(3) = i
End If
Next i
Else
'Read and store the column of interest from this
'row by reading the lineArray indices found above.
concatString = ""
For i = LBound(cols) To UBound(cols)
concatString = concatString & lineArray(i) & "_"
Next i
concatString = Left(concatString, Len(concatString) - 1)
frontSheet.Cells(frontSheetRow, 1).Value = concatString
frontSheetRow = frontSheetRow + 1
End If
Loop
ts.Close
End If
Next file
End Sub
You can find more information on FileSystemObject and TextStream here.