how change order of columns in csv file using VBA? - excel

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

Related

VBA slow due to pulling data from files

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

Importing and Sorting Text Files in Excel

I currently have a macro set up that allows me to paste data into column A from Textpad and then sorts, rounds, moves and saves the data as a txt file.
Is there anyway that I can modify the macro to allow me to import the txt file straight into Excel rather than having to copy and paste? The file names changes each time, but the file directory will stay the same.
This is the current macro I have that is run after manually copy and pasting the data into excel:
'Sub SortRoundandSave()
'
' SortTruncateandSave Macro
' This macro will sort, round and save your data
'
'
Selection.TextToColumns Destination:=Range("A1"), DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=True, Tab:=True, _
Semicolon:=False, Comma:=False, Space:=True, Other:=False, FieldInfo _
:=Array(Array(1, 1), Array(2, 1), Array(3, 1)), TrailingMinusNumbers:=True
Range("D1").Select
Selection.AutoFill Destination:=Range("D1:D" & Range("B" & Rows.Count).End(xlUp).Row)
Range("A:A,B:B,D:D").Select
Range("D1").Activate
Selection.Copy
Sheets("Truncated Data").Select
ActiveSheet.Paste
Sheets("Truncated Data").Select
Application.CutCopyMode = False
Sheets("Truncated Data").Move
ChDir "G:\XXXX\Folder\Name\ZZZZ\Sort"
ActiveWorkbook.SaveAs Filename:= _
"G:\XXXX\Folder\Name\ZZZZ\Sort\Sorted Data.txt", _
FileFormat:=xlText, CreateBackup:=False
Windows("Excel Truncator.xlsm").Activate
End Sub
I assume it needs a few lines before the text to columns part, but I cant seem to get one to work?
Any help would be greatly appreciated.
Thanks
Try this:
Sub SortRoundandSave()
'
' SortTruncateandSave Macro
' This macro will sort, round and save your data
'
Dim workSht As Worksheet: Set workSht = ActiveSheet 'ThisWorkbook.Sheets("") ' Enter the name of sheet
Dim FilePath As String
Dim strLine As String
Dim rowCnt As Long
With Application.FileDialog(msoFileDialogFilePicker)
.Title = "Select the file"
.Filters.Clear
.Filters.Add Description:="Text Files", Extensions:="*.txt"
'.InitialFileName = "G:\XXXX\Folder\Name" ' Optional: this is a startup directory, place the correct one and uncomment line
If .Show = 0 Then Exit Sub
FilePath = .SelectedItems(1)
End With
rowCnt = 1
Open FilePath For Input As #1
Do While Not EOF(1)
Line Input #1, strLine
workSht.Cells(rowCnt, 1) = strLine
rowCnt = rowCnt + 1
Loop
Close #1
With workSht
Range(.Cells(1, 1), .Cells(rowCnt - 1, 1)).TextToColumns Destination:=.Cells(1, 1), DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=True, Tab:=True, _
Semicolon:=False, Comma:=False, Space:=True, Other:=False, FieldInfo _
:=Array(Array(1, 1), Array(2, 1), Array(3, 1)), TrailingMinusNumbers:=True
.Cells(1, 4).AutoFill Destination:=Range(.Cells(1, 4), .Cells(workSht.Cells(Rows.Count, 2).End(xlUp).Row, 4)) ' "D1:D" & Range("B" & Rows.Count).End(xlUp).Row)
Range(.Cells(1, 1), .Cells(1, 4)).EntireColumn.Copy Sheets("Truncated Data").Cells(1, 1)
End With
Sheets("Truncated Data").Move
ActiveWorkbook.SaveAs Filename:= _
"G:\XXXX\Folder\Name\ZZZZ\Sort\Sorted Data.txt", _
FileFormat:=xlText, CreateBackup:=False
workSht.Parent.Activate
End Sub

using copy destination vba between workbooks

Been working a project using recorded macros to complete copying and pasting between workbooks. Recorded macros has been working BUT, when reading the forums people are stating copy/paste method takes more time for macro to run and is very inefficient. So I'm trying to sound out a copy destination vba line that would copy several columns starting from Range(A2:G2000) and then paste to range area starting at (B6:H2000). I'm not good at this and trying to learn more efficiency. Two things here come to mind. A simple copy and paste method which I have working. BUT would utilize the straight source = destination. Could this be done? After reading this you may see another issue. Why have down to Row 2000 selected and copy/pasted? You are correct in your thinking. Some reports(txt files) have 100 rows, some 300, none more than 1000 but I'm overdoing the copy selection because I'm won't be sure about future txt files. I was thinking if you could just select the column down to the last row used would be cool. This is way beyond me. I'd be happy just a new way to copy/paste efficiently.
I would appreciate any help that anyone could offer. let me know what you think.
Thanks
Boomer
enter code here
Sub import_data()
'
'
'import_data
'
Application.ScreenUpdating = False
'
'Opens the txt file in excel - text delimited and leaves file open until
we close at bottom of code. There is no 'name for this workbook.
Workbooks.OpenText (Module33.FileDir + "\cf_data.txt"), Origin:=437, _
StartRow:=1, DataType:=xlDelimited, TextQualifier:=xlDoubleQuote, _
ConsecutiveDelimiter:=False, Tab:=True, Semicolon:=False, Comma:=False _
, Space:=False, Other:=False, FieldInfo:=Array(Array(1, 1), Array(2, 1),
_
Array(3, 1), Array(4, 1), Array(5, 1), Array(6, 1)),
TrailingMinusNumbers:=True
'The line below is where I'm selecting data from the current opened
workbook and copying to another workbook
ActiveWindow.Sheet1.Range("A2:G2000").Copy
Destination:=Workbooks("Auto_Data.xlsm").Sheet2.Range ("B6:H2000")
'This info below is a (recorded marco). All works if I rem out the above
line and open up all the below lines
' Range("A2:G2000").Select
' Selection.Copy
' Windows("Auto_Data.xlsm").Activate
' Sheet2.Select
' Range("B6:H6").Select
' ActiveSheet.Paste
' Selection.AutoFilter
' Application.CutCopyMode = False
' ActiveWindow.ActivateNext
' ActiveWindow.Close
' Range("B4").Select
Application.ScreenUpdating = True
End Sub
A direct value transfer is typically faster than a copy and uses less memory since it doesn't involve the clipboard.
Sub import_data()
dim lr as long, arr as variant
dim wb1 as workbook
set wb1 = Workbooks.OpenText(filename:=Module33.FileDir & "\cf_data.txt"), Origin:=437, _
StartRow:=1, DataType:=xlDelimited, TextQualifier:=xlDoubleQuote, _
ConsecutiveDelimiter:=False, Tab:=True, Semicolon:=False, Comma:=False, _
Space:=False, Other:=False, FieldInfo:=Array(Array(1, 1), Array(2, 1), _
Array(3, 1), Array(4, 1), Array(5, 1), Array(6, 1)),
TrailingMinusNumbers:=True)
with wb1.sheets(1)
lr = .range("A:G").Find(what:="*", after:=.range("A1"), searchorder:=xlbyrows, _
searchdirection:=xlprevious).row
.range(.cells(2, "A"), .cells(lr, "G")).value
end with
wb1.close
Workbooks("Auto_Data.xlsm").Sheet2.Range("B6").resize(ubound(arr, 1), ubound(arr, 2)) = arr
end sub

How to open and extract information from multiple files in VBA

I have around 30 files that I want to perform the same analysis on. Ideally, I want VBA to open all files and extract a certain (identical) piece of information. However, I don't know how to write a function for it. I was thinking of saving all the files as CSV and importing to python (a language I'm familiar with) which would make it easier for my data analysis. The reason I'm importing into excel is because python has difficulty reading .TX0 files (parsing line by line would be time consuming).
This is what i Have for the csv conversion. How do i translate this into the extraction of multiple files?
Sub TX0_CSV()
'
' TX0_CSV Macro
'
'
Workbooks.OpenText Filename:="X/.....fid002.TX0", Origin:= _
xlMSDOS, StartRow:=1, DataType:=xlDelimited, TextQualifier:=xlDoubleQuote _
, ConsecutiveDelimiter:=False, Tab:=True, Semicolon:=False, Comma:=True _
, Space:=False, Other:=False, FieldInfo:=Array(Array(1, 1), Array(2, 1), _
Array(3, 1), Array(4, 1)), TrailingMinusNumbers:=True
Range("A1:O13").Select
Range("O13").Activate
Selection.ClearContents
Rows("15:16").Select
Selection.Delete Shift:=xlUp
ActiveWindow.SmallScroll Down:=9
Range("A20:H29").Select
Range("H29").Activate
Selection.ClearContents
Range("J19").Select
ActiveWorkbook.SaveAs Filename:="X:\Joey\FID002.csv", FileFormat:=xlCSV, _
CreateBackup:=False
End Sub
You could convert it to a sub and then repeatedly call it.
Here is an example (Untested) Also note how we got rid of .Activate and .Select. You may want to see This
Sub ConvertFile(flName As String, newFileName As String)
Dim wb As Workbook
Dim ws As Worksheet
Workbooks.OpenText Filename:=flName, Origin:= _
xlMSDOS, StartRow:=1, DataType:=xlDelimited, TextQualifier:=xlDoubleQuote _
, ConsecutiveDelimiter:=False, Tab:=True, Semicolon:=False, Comma:=True _
, Space:=False, Other:=False, FieldInfo:=Array(Array(1, 1), Array(2, 1), _
Array(3, 1), Array(4, 1)), TrailingMinusNumbers:=True
Set wb = ActiveWorkbook
Set ws = wb.Sheets(1)
With ws
.Range("A1:O13").ClearContents
.Rows("15:16").Delete Shift:=xlUp
.Range("A20:H29").ClearContents
End With
wb.SaveAs Filename:=newFileName, FileFormat:=xlCSV
wb.Close (False)
End Sub
Example
Sub Sample()
ConvertFile "C:\Test1.dat", "C:\Test2.dat"
End Sub

Excel, VBA, I need to sent rng to lastcolumn. Currently MsgBox will display it

basically i am using the TextToColumns function to separate out data separated by a semi colon in the same cell. problem is there are 2 columns of data that needs this function done and i have to insert the data without overwriting.
(go easy, first time with VBA and excel) this is what i currently have:
Sub Button1_Click()
Dim rng As Range
Dim sh As Worksheet
Set sh = Worksheets("Sheet1")
With sh
Set rng = .[Q1]
Set rng = .Range(rng, .Cells(.Rows.Count, rng.Column).End(xlUp))
num = Application.WorksheetFunction.Max(Columns("P"))
rng.Offset(0, 1).Resize(1, num).EntireColumn.Insert
rng.TextToColumns Destination:=rng, DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=False, _
Semicolon:=True, Comma:=False, Space:=False, Other:=False, _
FieldInfo:=Array(Array(1, 1), Array(2, 1), Array(3, 1)), TrailingMinusNumbers:=True
End With
Set sh2 = Worksheets("Sheet1")
With sh2
num2 = Application.WorksheetFunction.Max(Columns("P"))
Dim lastColumn As Integer
lastColumn = ActiveSheet.UsedRange.Column - 1 + ActiveSheet.UsedRange.Columns.Count
MsgBox Replace(Cells(1, lastColumn).Address(False, False), "1", "")
MsgBox lastColumn
Set rng = .[W1]
Set rng = .Range(rng, .Cells(.Rows.Count, rng.Column).End(xlUp))
rng.TextToColumns Destination:=rng, DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=False, _
Semicolon:=True, Comma:=False, Space:=False, Other:=False, _
FieldInfo:=Array(Array(1, 1), Array(2, 1), Array(3, 1)), TrailingMinusNumbers:=True
End With
End Sub
ok so what i am trying to fix is setting the rng manually in the second part to W1. the rng needs to be the next empty column. so lastColumn using the MsgBox DOES return the column "W" but i cannot set that to rng (type mismatch). oh and the num variable is set to the amount of columns i need to insert. my data looks like this:
count | column with ; data need separating | column with ; data need separating
5 | 5 sets of data separated by semi colons | don't care because this is the end of sheet
is there any easier way to do this? am i even close?
... Easiest solution if I understand your question correctly... Why don't you just make a THIRD column that equals Column1 & ";" & Column2, then just do text-to-columns on that single column??
Or am I missing something??
Assuming I'm understanding your setup correctly, the following code should work.
If you process the data columns from right to left, you don't have to worry about the change in address references when the columns are inserted. That means you can use a single block of insertion/conversion code, iterated over the two data address references, which I've assumed are Q1 and R1.
Note also that I added an offset to the TextToColumns destination to avoid overwriting the original data.
Option Explicit
Sub myTextToColumns()
Dim sh As Worksheet
Dim rng As Range
Dim num As Long
Dim arr As Variant
Dim i As Long
Set sh = Worksheets("Sheet1")
arr = Array("R1", "Q1")
num = Application.WorksheetFunction.Max(Columns("P"))
With sh
For i = LBound(arr) To UBound(arr)
Set rng = .Range(arr(i))
Set rng = .Range(rng, .Cells(.Rows.Count, rng.Column).End(xlUp))
rng.Offset(0, 1).Resize(1, num).EntireColumn.Insert
rng.TextToColumns Destination:=rng.Offset(0, 1), DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=False, _
Semicolon:=True, Comma:=False, Space:=False, Other:=False, _
FieldInfo:=Array(Array(1, 1), Array(2, 1), Array(3, 1)), TrailingMinusNumbers:=True
Next
End With
End Sub

Resources