My Excel VBA script pulls data from other files, and my script isn't very good. How can I speed the file up?
So I pull 11x2737 data from each of 8 text files and pull 3x70101 from each of another 8 text files. It takes over 2 minutes to do this.
Set conFolder = CreateObject("Scripting.FileSystemObject")
For Each conFile In conFolder.GetFolder(folderName).Files
If InStr(conFile, "con.dat") > 0 Then
Set WorkB4 = Workbooks.Open(Filename:=conFile)
WorkB4.Activate
WorkB4.Application.DisplayAlerts = False
Columns("A:A").Select
Selection.TextToColumns Destination:=Range("A1"), DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=False, _
Semicolon:=False, Comma:=True, Space:=False, Other:=False, FieldInfo _
:=Array(Array(1, 1), Array(2, 1), Array(3, 1), Array(4, 1), Array(5, 1), Array(6, 1), _
Array(7, 1), Array(8, 1), Array(9, 1), Array(10, 1), Array(11, 1)), _
TrailingMinusNumbers:=True
Cells.Select
Selection.Copy
conBottle = Left(Right(conFile, 9), 1)
WorkB1.Activate
Sheets("Bot" & conBottle).Select
Range("A1").Select
ActiveSheet.Paste
WorkB4.Application.DisplayAlerts = True
WorkB4.Application.CutCopyMode = False
WorkB4.Close SaveChanges:=False
End If
Next
I'm hoping there's a way to pull this data as fast as possible (ideally within 5 seconds).
Avoiding Select and Activate, turning off ScreenUpdating, and skipping the clipboard should help, but typically the biggest bottleneck would be network or disk I/O: if the text files are on a network share, try copying them locally first.
So I refactored the code a bit, and there's only WorkB1 I couldn't work out where it came from.
None of this is tested, but it should give you a workable starting point.
Option Explicit
Public Sub ProcessFiles(ByVal Path As String)
Dim WorkB1 As Workbook ' <~
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Application.Calculation = xlCalculationManual
On Error GoTo CleanFail
With CreateObject("Scripting.FileSystemObject")
Dim conFolder As Object
Set conFolder = .GetFolder(Path)
Dim conFile As Variant '/String
For Each conFile In conFolder.Files
If InStr(conFile, "con.dat", VbCompareMethod.vbTextCompare) > 0 Then
ProcessFile conFile, WorkB1
End If
Next
End With
CleanExit:
Application.ScreenUpdating = True
Application.DisplayAlerts = False
Application.Calculation = xlCalculationAutomatic
Exit Sub
CleanFail:
Debug.Print Err.Description
Resume CleanExit
End Sub
Private Sub ProcessFile(ByVal conFile As String, ByVal WorkB1 As Workbook)
On Error GoTo CleanFail
Dim book As Workbook
Set book = Workbooks.Open(conFile)
Dim sheet As Worksheet
Set sheet = book.Worksheets(1)
Dim dataRange As Range
Set dataRange = sheet.Columns(1)
Const NumberOfColumns As Long = 11
dataRange.TextToColumns _
destination:=sheet.Range("A1"), _
DataType:=xlDelimited, _
TextQualifier:=xlTextQualifierDoubleQuote, _
ConsecutiveDelimiter:=False, _
Tab:=False, _
Semicolon:=False, _
Comma:=True, _
Space:=False, _
Other:=False, _
FieldInfo:=Array( _
Array(1, 1), _
Array(2, 1), _
Array(3, 1), _
Array(4, 1), _
Array(5, 1), _
Array(6, 1), _
Array(7, 1), _
Array(8, 1), _
Array(9, 1), _
Array(10, 1), _
Array(11, 1)), _
TrailingMinusNumbers:=True
Dim dataRows As Long
dataRows = sheet.Range("A" & sheet.Rows.Count).End(xlUp).Row
Dim sourceRange As Range
Set sourceRange = sheet.Range("A1", sheet.Cells(dataRows, NumberOfColumns))
Debug.Print "Source: " & sourceRange.Address(External:=True)
Dim conBotName As String
conBotName = Left$(Right$(conFile, 9), 1)
Dim conBotSheet As Worksheet
Set conBotSheet = WorkB1.Worksheets("Bot" & conBotName)
Dim destination As Range
Set destination = conBotSheet.Range("A1", conBotSheet.Cells(dataRows, NumberOfColumns))
Debug.Print "Destination: " & destination.Address(External:=True)
destination.Value = sourceRange.Value
book.Close SaveChanges:=False
CleanExit:
Exit Sub
CleanFail:
Debug.Print Err.Description
Resume CleanExit
End Sub
Related
I'd like to keep a cell with blank when there is no data.
Keep a cell with blank
I like to keep C3 as Empty cell like this Sample.
But My VBA gave me Sample.
Can anyone help me?
My code is:
FileToOpen = Application.GetOpenFilename(FileFilter:="Text Files(*.txt),*txt", MultiSelect:=True)
If IsArray(FileToOpen) Then
Application.ScreenUpdating = False
For i = 1 To UBound(FileToOpen)
Workbooks.OpenText _
Filename:=FileToOpen(i), _
StartRow:=1, _
DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, _
ConsecutiveDelimiter:=True, _
Tab:=True, _
Comma:=True, _
FieldInfo:=Array(Array(1, 2), Array(2, 2), Array(3, 2), Array(4, 1), _
Array(5, 2), Array(6, 2), Array(7, 2), Array(8, 2), Array(9, 2))
Set wbTextImport = ActiveWorkbook
wbTextImport.Worksheets(1).Range("A1").CurrentRegion.Copy
wsMaster.Activate
Range("A" & tgRow).Select
ActiveSheet.Paste
Application.CutCopyMode = False
wbTextImport.Close False
wsMaster.Rows(tgRow).Delete Shift:=xlUp
tgRow = wsMaster.Cells(wsMaster.Rows.Count, 1).End(xlUp).Row + 1
Next i
I have a code to open text files to copy included data and paste it in the excel file, but while select multiple files the code run only for one file and i want to run it for all selectet files
CWB is the main file
NWB is the file to copy from it
The code
Sub Import_Reports()
' Difine References
Dim CWB As Excel.Workbook
Dim NWB As Excel.Workbook
Dim FN As String
Dim FD As FileDialog
Set CWB = ThisWorkbook
Set FD = Application.FileDialog(msoFileDialogFilePicker)
With FD
.AllowMultiSelect = True
.Filters.Add "Excel Files or Text or CSV", "*.xls; *.xlsx; *.xlsm; *.xlsb; *.csv; *.txt", 1
.Show
If .SelectedItems.Count > 0 Then
FN = .SelectedItems(1)
Workbooks.OpenText Filename:=FN, _
Origin:=65001, StartRow:=1, DataType:=xlDelimited, TextQualifier:= _
xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=True, Semicolon:=False, _
Comma:=True, Space:=False, Other:=False, FieldInfo:=Array(Array(1, 2), _
Array(2, 2), Array(3, 2), Array(4, 4), Array(5, 1), Array(6, 2), Array(7, 2), Array(8, 2), _
Array(9, 4), Array(10, 1), Array(11, 1), Array(12, 4), Array(13, 2), Array(14, 2), Array(15 _
, 1), Array(16, 1), Array(17, 4), Array(18, 4), Array(19, 1), Array(20, 1), Array(21, 1), _
Array(22, 1)), TrailingMinusNumbers:=True
Set NWB = ActiveWorkbook
NWB.Activate
ActiveSheet.Select
Dim LastRow As Long
LastRow = Range("B" & Rows.Count).End(xlUp).Row
Range("A2:V" & LastRow).Select
Selection.Copy
CWB.Activate
Sheets("Payroll Report").Select
LastRow = Range("B" & Rows.Count).End(xlUp).Row + 1
Range("A" & LastRow).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Application.CutCopyMode = False
Cells.Select
Selection.SpecialCells(xlCellTypeLastCell).Select
Selection.EntireRow.Delete
Range("A" & LastRow).Select
NWB.Close SaveChanges:=False
Else
Exit Sub
End If
End With
End Sub
Move the copying code to a separate subroutine that you can call for each file.
Option Explicit
Sub Import_Reports()
' Define References
Dim CWB As Excel.Workbook
Dim FD As FileDialog, n
Set CWB = ThisWorkbook
Set FD = Application.FileDialog(msoFileDialogFilePicker)
With FD
.AllowMultiSelect = True
.Filters.Add "Excel Files or Text or CSV", "*.xls; *.xlsx; *.xlsm; *.xlsb; *.csv; *.txt", 1
.Show
If .SelectedItems.Count = 0 Then Exit Sub
For n = 1 To .SelectedItems.Count
Call ImportTextFile(CWB, .SelectedItems(n))
Next
End With
MsgBox n - 1 & " files imported", vbInformation
End Sub
Sub ImportTextFile(CWB As Workbook, filename As String)
Workbooks.OpenText filename:=filename, _
Origin:=65001, StartRow:=1, DataType:=xlDelimited, TextQualifier:= _
xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=True, Semicolon:=False, _
Comma:=True, Space:=False, Other:=False, FieldInfo:=Array(Array(1, 2), _
Array(2, 2), Array(3, 2), Array(4, 4), Array(5, 1), Array(6, 2), Array(7, 2), Array(8, 2), _
Array(9, 4), Array(10, 1), Array(11, 1), Array(12, 4), Array(13, 2), Array(14, 2), Array(15 _
, 1), Array(16, 1), Array(17, 4), Array(18, 4), Array(19, 1), Array(20, 1), Array(21, 1), _
Array(22, 1)), TrailingMinusNumbers:=True
Dim LastRow As Long, ar
With ActiveWorkbook.Sheets(1)
LastRow = .Range("B" & .Rows.Count).End(xlUp).Row
' copy values to array except last row
ar = .Range("A2:V" & LastRow - 1).Value2
End With
ActiveWorkbook.Close SaveChanges:=False
' copy array to CWB
With CWB.Sheets("Payroll Report")
LastRow = .Range("B" & .Rows.Count).End(xlUp).Row + 1
.Range("A" & LastRow).Resize(UBound(ar), UBound(ar, 2)) = ar
End With
End Sub
Import Text Files
Option Explicit
Sub Import_Reports()
Dim FD As FileDialog
Set FD = Application.FileDialog(msoFileDialogFilePicker)
Dim collFilePaths As Object
With FD
.AllowMultiSelect = True
.Filters.Add "Excel Files or Text or CSV", "*.xls; *.xlsx; *.xlsm; *.xlsb; *.csv; *.txt", 1
.Show
If .SelectedItems.Count = 0 Then
MsgBox "You canceled.", vbExclamation
Exit Sub
Else
Set collFilePaths = .SelectedItems
End If
End With
Dim CWB As Workbook: Set CWB = ThisWorkbook
Dim cws As Worksheet: Set cws = CWB.Worksheets("Payroll Report")
Dim cfrrg As Range
Set cfrrg = cws.Range("B" & cws.Rows.Count).End(xlUp) _
.Offset(1).EntireRow.Columns("A:V")
Application.ScreenUpdating = False
Dim FilePath As Variant
Dim NWB As Workbook
Dim nws As Worksheet
Dim nrg As Range
Dim nLastRow As Long
Dim crg As Range
For Each FilePath In collFilePaths
'Set NWB = Workbooks.Open(FilePath) ' tested with this line
On Error Resume Next
Set NWB = Workbooks.OpenText(Filename:=CStr(FilePath), _
Origin:=65001, StartRow:=1, DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, _
Tab:=True, Semicolon:=False, Comma:=True, Space:=False, _
Other:=False, FieldInfo:=Array(Array(1, 2), Array(2, 2), _
Array(3, 2), Array(4, 4), Array(5, 1), Array(6, 2), _
Array(7, 2), Array(8, 2), Array(9, 4), Array(10, 1), _
Array(11, 1), Array(12, 4), Array(13, 2), Array(14, 2), _
Array(15, 1), Array(16, 1), Array(17, 4), Array(18, 4), _
Array(19, 1), Array(20, 1), Array(21, 1), Array(22, 1)), _
TrailingMinusNumbers:=True)
On Error GoTo 0
If Not NWB Is Nothing Then
Set nws = NWB.Worksheets(1)
' Delete last row = Don't Copy Last row - '- 1' ???
nLastRow = nws.Range("B" & nws.Rows.Count).End(xlUp).Row - 1
If nLastRow >= 2 Then
Set nrg = nws.Range("A2:V" & nLastRow)
nLastRow = nLastRow - 1
Set crg = cfrrg.Resize(nLastRow)
crg.Value = nrg.Value
Set cfrrg = cfrrg.Offset(nLastRow)
End If
NWB.Close SaveChanges:=False
Set NWB = Nothing
End If
Next FilePath
cws.Activate
cfrrg.Cells(1).Select
'CWB.Save
Application.ScreenUpdating = True
MsgBox "Reports imported.", vbInformation
End Sub
I'm trying to automate a report making, i have to copy/paste data from .txt files that are in the same carpet, to do so i use a window because using the path is inefficient when using in other computers.
Errors i encounter:
When saving the new Workbook i use .xlsx or .xls because it throws me an error of data compatibility and the workbook doesn't load or the format is not correct (The format and the extension of the file "My FILE" don't match. The file maybe damaged or not be safe. Dont open it unless you trust the origin ¿ Would you like to open it ?")
I want the data type of all the cells to be text so i can transform the date into dd/mm/yyyy
I have to delete all the spaces that are in the columns so i can add leading zeros into two columns.
I've tried tons of macros i've made but i can't fix the errors.
Here is the latest code i made for the automation, i'm still learning VBA.
Sub REP_DET_Report()
Dim xFd As FileDialog
Dim xFdItem As Variant
Dim xFileName As String
Set xFd = Application.FileDialog(msoFileDialogFolderPicker)
If xFd.Show = -1 Then
xFdItem = xFd.SelectedItems(1) & Application.PathSeparator
xFileName = Dir(xFdItem & "*.txt*")
Do While xFileName <> ""
With Workbooks.Open(xFdItem & xFileName)
Dim objRange1 As Range
'Set up the ranges
Set objRange1 = Range("A1:A1048576")
'Do the first parse
objRange1.TextToColumns _
Destination:=Range("A1"), _
FieldInfo:=Array(Array(1, xlTextFormat), Array(2, xlTextFormat), Array(3, xlTextFormat), Array(4, xlTextFormat), Array(5, xlTextFormat), Array(6, xlTextFormat), Array(7, xlTextFormat), Array(8, xlTextFormat), Array(9, xlTextFormat), Array(10, xlTextFormat)), _
DataType:=xlDelimited, _
Tab:=False, _
Semicolon:=False, _
Comma:=False, _
Space:=False, _
Other:=True, _
OtherChar:="|"
Dim IntialName As String
Dim sFileSaveName As Variant
IntialName = "Sample"
sFileSaveName = Application.GetSaveAsFilename(InitialFileName:=InitialName, FileFilter:="Libro de Excel(*.xls), *.xls")
If sFileSaveName <> False Then
ActiveWorkbook.SaveAs sFileSaveName
End If
End With
xFileName = Dir
Loop
End If
End Sub
Also i made another code so i can paste the .txt in the same workbook but in different worksheets, the issue with this one is that it modifies the first file but the rest don't.
Sub REP_DET_Report()
On Error Resume Next
myBook = ActiveWorkbook.Name
Set nav = CreateObject("shell.application")
folder = nav.browseforfolder(0, "PICK FOLDER", 0, "c:\").items.Item.Path
ChDir folder & "\"
file = Dir("*.txt")
Do While file <> ""
Workbooks.OpenText file, origin:=xlWindows, startrow:=1, DataType:=xlDelimited
Dim objRange1 As Range
'Set up the ranges
Set objRange1 = Range("A1:A1048576")
'Do the first parse
objRange1.TextToColumns _
Destination:=Range("A1"), _
FieldInfo:=Array(Array(1, xlTextFormat), Array(2, xlTextFormat), Array(3, xlTextFormat), Array(4, xlTextFormat), Array(5, xlTextFormat), Array(6, xlTextFormat), Array(7, xlTextFormat), Array(8, xlTextFormat), Array(9, xlTextFormat), Array(10, xlTextFormat)), _
DataType:=xlDelimited, _
Tab:=False, _
Semicolon:=False, _
Comma:=False, _
Space:=False, _
other:=True, _
OtherChar:="|"
other = ActiveWorkbook.Name
ActiveSheet.Copy before:=Workbooks(myBook).Sheets(1)
Workbooks(other).Close False
file = Dir()
Loop
End Sub
´´´
I am reusing code Import Multiple text files into workbook where worksheet name matches text file name
This code is creating multiple worksheets and importing pipe delimited data into individual columns.
I need all the cells to be set to Text qualified before it does the text to columns.
Basically I want all the columns to be in text format instead of default General as the 16 digit numbers that I have in my file are getting messed up with General format.
I did try to put below lines but it changes the format after text to column is completed.
cells.select
Selection.NumberFormat = "#"
Here is the code that I am using
Sub Extract()
Dim FilesToOpen
Dim x As Integer
Dim wkbAll As Workbook
Dim sDelimiter As String
On Error GoTo ErrHandler
Application.ScreenUpdating = False
sDelimiter = "|"
FilesToOpen = Application.GetOpenFilename _
(FileFilter:="Text Files (*.txt), *.txt", _
MultiSelect:=True, Title:="Text Files to Open")
If TypeName(FilesToOpen) = "Boolean" Then
MsgBox "No Files were selected"
GoTo ExitHandler
End If
Set wkbAll = Application.ActiveWorkbook
x = 1
With Workbooks.Open(Filename:=FilesToOpen(x))
.Worksheets(1).Columns("A:A").TextToColumns _
Destination:=Range("A1"), DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, _
Tab:=False, Semicolon:=False, Comma:=False, Space:=False, _
Other:=True, OtherChar:="|"
.Sheets(1).Copy After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count)
.Close False
End With
x = x + 1
While x <= UBound(FilesToOpen)
With Workbooks.Open(Filename:=FilesToOpen(x))
.Worksheets(1).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
.Sheets(1).Move After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count)
End With
x = x + 1
Wend
wkbAll.Save
ExitHandler:
Application.ScreenUpdating = True
Set wkbAll = Nothing
Exit Sub
ErrHandler:
MsgBox Err.Description
Resume ExitHandler
End Sub
Try this (I haven't). It (hopefully) sets all cells in the sheet to text. With see commented section for the addition.
Sub Extract()
Dim FilesToOpen
Dim x As Integer
Dim wkbAll As Workbook
Dim sDelimiter As String
On Error GoTo ErrHandler
Application.ScreenUpdating = False
sDelimiter = "|"
FilesToOpen = Application.GetOpenFilename _
(FileFilter:="Text Files (*.txt), *.txt", _
MultiSelect:=True, Title:="Text Files to Open")
If TypeName(FilesToOpen) = "Boolean" Then
MsgBox "No Files were selected"
GoTo ExitHandler
End If
Set wkbAll = Application.ActiveWorkbook
x = 1
With Workbooks.Open(Filename:=FilesToOpen(x))
' ---------------------------------------------------
.Worksheets(1).Cells.NumberFormat = "#"
' ---------------------------------------------------
.Worksheets(1).Columns("A:A").TextToColumns _
Destination:=Range("A1"), DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, _
Tab:=False, Semicolon:=False, Comma:=False, Space:=False, _
Other:=True, OtherChar:="|"
.Sheets(1).Copy After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count)
.Close False
End With
x = x + 1
While x <= UBound(FilesToOpen)
With Workbooks.Open(Filename:=FilesToOpen(x))
.Worksheets(1).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
.Sheets(1).Move After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count)
End With
x = x + 1
Wend
wkbAll.Save
ExitHandler:
Application.ScreenUpdating = True
Set wkbAll = Nothing
Exit Sub
ErrHandler:
MsgBox Err.Description
Resume ExitHandler
End Sub
Not the permanent solution but I added below change which looks like resolved my problem. Since the longest record in one of my file has 45 cells I auto recorded below Macro and appended to my code after OtherChar:="|" and now it is working as I wanted.
OtherChar:="|", FieldInfo:=Array(Array(1, 2), Array(2, 2), Array(3, 2), Array(4, 2), Array(5, _
2), Array(6, 2), Array(7, 2), Array(8, 2), Array(9, 2), Array(10, 2), Array(11, 2), Array(12 _
, 2), Array(13, 2), Array(14, 2), Array(15, 2), Array(16, 2), Array(17, 2), Array(18, 2), _
Array(19, 2), Array(20, 2), Array(21, 2), Array(22, 2), Array(23, 2), Array(24, 2), Array( _
25, 2), Array(26, 2), Array(27, 2), Array(28, 2), Array(29, 2), Array(30, 2), Array(31, 2), _
Array(32, 2), Array(33, 2), Array(34, 2), Array(35, 2), Array(36, 2), Array(37, 2), Array( _
38, 2), Array(39, 2), Array(40, 2), Array(41, 2), Array(42, 2), Array(43, 2), Array(44, 2), _
Array(45, 2)), TrailingMinusNumbers:=True
I have 3 csv files which I have to merge and but before that I have to prepare then to have same columns order. All works fine except for I cannot figure out so far how change order of columns in output file. I can select columns which I want and other skips fine but what if I want to swap some? I thought that putting in proper order in fieldinfo array would do the trick but no. I want to swap 8 with 6.
Application.ScreenUpdating = False
Workbooks.OpenText Filename:=Filenamenew, Origin:=xlWindows, StartRow _
:=2, DataType:=xlDelimited, TextQualifier:=xlDoubleQuote, _
ConsecutiveDelimiter:=False, Tab:=False, Semicolon:=False, Comma:=True, _
Space:=False, Other:=False, FieldInfo:=Array(Array(1, 3), Array(2, 9), Array(3, 1), Array(4, 9), Array(5, 9), Array(8, 1), Array(7, 9), Array(6, 1))
Set Wb = ActiveWorkbook
Application.DisplayAlerts = False
Wb.SaveAs Filename:=LBname, FileFormat:=FileFormatNum, _
ReadOnlyRecommended:=False, _
CreateBackup:=False
Application.DisplayAlerts = True
Wb.Close savechanges:=False
thanks
The best way to do this is to change the output of whatever is creating the CSV file you need to change. I assume you don't have access to that for whatever reason, so this will get the job done:
Sub swapColumns(first As Integer, second As Integer)
Dim wb As Workbook
Dim ws As Worksheet
Set wb = Workbooks.Open("C:\root\test.csv")
Set ws = wb.Sheets(1)
If first > second Then
Dim i As Integer
i = first
first = second
second = i
ElseIf first = second Then
Exit Sub
End If
ws.Columns(second).Cut
ws.Columns(first).Insert Shift:=xlToRight
ws.Columns(first + 1).Cut
ws.Columns(second + 1).Insert Shift:=xlToRight
End Sub
You can call this Sub from your existing code with swapColumns 6, 8