Trim ref text posted in Excel VBA editor - vba

enter code hereI have my following code a bit short in the process of working on it, so I am trying to get text from a .txt file to be displayed in a cell on Excel, the code will be
Sub citi()
Dim c As Range
Open "C:\Users\alvaradod\Desktop\citi macro\Import File.txt" For Input As #1
R = 0
Dim i As Range
Dim num As Integer
Dim arrData() As String
the_value = Sheets("Prog").Range("A1")
Do Until EOF(1)
Line Input #1, Data
If Not Left(Data, 1) = "" Then
'import this row
R = R + 1
Cells(R, 1).Value = Data
'Mid(the_value, 3, 5)
'Left(Data, Len(Data) - 3)).Value
End If
Loop
For Each i In Range("A1")
i.Select
ActiveCell.Rows("1:1").Mid(Data(i), 49, 5).Select
'ActiveCell.Rows("1:1").EntireRow.Select
Selection.Copy
Sheets("Import").Range("A1").End(xlUp).Offset(num, 0).PasteSpecial
ActiveCell.Rows.Delete
num = num + 1
Next i
End Sub
" LINE 11 WILL PAST THE TEXT FROM LINE ONE ON .TXT FILE TO EXCEL, AFTER THIS FUNCTION I NEED TO TRIM THIS SAME TEXT IN THE EXCEL SHEET TO SHOW THE FIRST 5 CHARACTERS"

Your question isn't very clear, but perhaps something like this?
Sub citi()
Dim oFSO As Object
Dim arrData() As String
Dim arrImport1(1 To 65000) As String
Dim arrImport2(1 To 65000) As String
Dim i As Long, j As Long
Set oFSO = CreateObject("Scripting.FileSystemObject")
arrData = Split(oFSO.OpenTextFile("C:\Test\test.txt").ReadAll, vbCrLf)
For i = LBound(arrData) To UBound(arrData)
If Len(arrData(i)) > 0 Then
j = j + 1
arrImport1(j) = Mid(arrData(i), 3, 5)
arrImport2(j) = Mid(arrData(i), 49, 5)
End If
Next i
If j > 0 Then
Sheets("Sheet1").Range("A1").Resize(j).Value = Application.Transpose(arrImport1)
Sheets("Sheet2").Range("A1").Resize(j).Value = Application.Transpose(arrImport2)
End If
Set oFSO = Nothing
Erase arrData
Erase arrImport
End Sub

Related

Efficiency problems moving data from CSV -> excel cells

I started VBA - programming 2 days ago and I'm having efficiency problems given my limited knowledge of VBA and EXCEL.
I'm moving data from .CSV to .xlsm files. The .CSV file i receive is structured as
SHEET;COL;ROW;VALUE.
This .CSV is then read to a multidimension array and populates an excel file withwb.Worksheets(ARRAY(i, SHEET)).Cells(R,C) = ARRAY(i, VALUE)
To my understanding, applying the array to a range of cells does not work, as there is no continuous surface to which i'm sending each individual .csv row.
What i've tried most of it can be seen below. I believe a big issue i'm having is the pass-through between VBA -> EXCEL for each .CSV row. Is there any way this can be done by bulk instead?
All types of comments about efficiency and general how-to in VBA is greatly appreciated!
Option Explicit
Private Sub imp_Data()
'----------------------------File Dialog for data input-----------------
Dim Valarr As Variant
Dim fullpath As String
Dim CSVSHEET As Integer, CSVCOL As Integer, CSVROW As Integer, CSVVALUE As Integer
fullpath = [YOUR TEST FILE.CSV]
'----------------------------Read rawdata----------------------------
Dim RawData As String
Open fullpath For Binary As #1
RawData = Space$(LOF(1))
Get #1, , RawData
Close #1
'----------------------------Split rawdata into array-------------------
Dim r As Long, Nrow As Long, Ncol As Long
Dim c As Integer
Dim lineArr As Variant, cellArr As Variant
If Len(RawData) > 0 Then
'Split each row in CSV to str array
lineArr = Split(Trim$(RawData), vbCrLf)
'Dim final array
Nrow = UBound(lineArr) + 1
Ncol = UBound(Split(lineArr(0), ";")) + 1
ReDim Valarr(1 To Nrow, 1 To Ncol)
'Split each col on delimiter ";"
For r = 1 To Nrow
If Len(lineArr(r - 1)) > 0 Then
cellArr = Split(lineArr(r - 1), ";")
For c = 1 To Ncol
Valarr(r, c) = cellArr(c - 1)
Next c
End If
Next r
Else
Debug.Print "No data read"
' do more stuff
End If
'----------------------------Read Table positions-----------------------
Dim i As Integer
For i = 1 To Ncol
If UCase(Valarr(1, i)) = "SHEET" Then
CSVSHEET = i
ElseIf UCase(Valarr(1, i)) = "COL" Then
CSVCOL = i
ElseIf UCase(Valarr(1, i)) = "ROW" Then
CSVROW = i
ElseIf UCase(Valarr(1, i)) = "VALUE" Then
CSVVALUE = i
End If
Next i
'Turn off calculation and screen update for efficiency
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
'--------------------------------------------Send data to Cells----------
Dim L As Long
Dim wb As Workbook
Set wb = ThisWorkbook
L = UBound(Valarr, 1) - LBound(Valarr, 1) + 1
For i = 2 To L
If IsEmpty(Valarr(i, 1)) = 0 Then
wb.Worksheets(Valarr(i, CSVSHEET)).Cells(Valarr(i, CSVROW), Valarr(i, CSVCOL)) = Valarr(i, CSVVALUE)
End If
Next i
'Release ValArr memory
ReDim Valarr(0)
Erase Valarr
'Reapply calculation/screen update
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub
From tests with 1 million rows it takes 14 seconds to read data to array and 5+ minutes to move the data to their designated cell. So the issue in the code below is (what i believe)
For i = 2 To L
If IsEmpty(Valarr(i, 1)) = 0 Then
wb.Worksheets(Valarr(i, CSVSHEET)).Cells(Valarr(i, CSVROW), Valarr(i, CSVCOL)) = Valarr(i, CSVVALUE)
End If
Next i

How to open a very large .dat file using excel vba

I have some data files (.dat) that are very large (exceed the 1,048,000 rows Excel allows). I can't quite figure out what the problem is with the attempted macros (originally written for text files with "," delimiter, not .dat files with tab delimiter). The macro works, however it causes the data to be compiled into one column (ex. supposed to be 5 columns, now 1 column with all the numbers as a long text string). Is there a better way to open a very large .dat file, split it up and import it into separate worksheets while keeping the data in separate columns using the tab delimiter?
Sub ImportBigFile()
Dim N As Long
Dim Lim As Long
Dim SS() As String
Dim S As String
Dim R As Long
Dim C As Long
Dim WS As Worksheet
Dim FNum As Integer
Dim FName As String
FName = "C:\Folder 1\Folder 2\File.dat"
FNum = FreeFile
With ActiveWorkbook.Worksheets
Set WS = .Add(after:=.Item(.Count))
End With
Lim = WS.Rows.Count
Open FName For Input Access Read As #FNum
R = 0
Do Until EOF(FNum)
R = R + 1
Line Input #FNum, S
SS = Split(S, "\t", -1)
For C = LBound(SS) To UBound(SS)
WS.Cells(R, C + 1).Value = SS(C)
Next C
If R = Lim Then
With ActiveWorkbook.Worksheets
Set WS = .Add(after:=.Item(.Count))
End With
R = 0
End If
Loop
End Sub
SS = Split(S, "\t", -1)
should be
SS = Split(S, chr$(9), -1)
Assuming your tab is ascii
This fixes 2 issues, and improves performance
As mentioned, the delimiter used in Split (vbTab)
You open the file for Input but never close it
Uses an array to convert to range format, then places it on the range in one operation
Test file used contains 3,145,731 Rows and 5 Cols (122 Mb)
your code: 3.9 min (231.755 sec)
this code: 1.1 Min ( 64.966 sec)
Option Explicit
Public Sub ImportBigFile2()
Const fName = "C:\Folder 1\Folder 2\File.dat"
Dim maxR As Long, maxC As Long, wsCount As Long, arr As Variant, rng As Variant
Dim fNum As Long, fText As String, ws As Worksheet, ln As Variant, nextR As Long
Dim i As Long, r As Long, c As Long, t As Double, ubArr As Long
t = Timer: fNum = FreeFile: maxR = ThisWorkbook.Worksheets(1).Rows.Count
Open fName For Input Access Read As #fNum
fText = Input$(LOF(1), 1)
Close #fNum
arr = Split(fText, vbCrLf): ubArr = UBound(arr)
maxC = UBound(Split(arr(0), vbTab)) + 1
wsCount = ubArr \ maxR + 1: nextR = 0
Application.ScreenUpdating = False
With ThisWorkbook.Worksheets
For i = 1 To wsCount
Set ws = .Add(After:=.Item(.Count))
ReDim rng(1 To maxR, 1 To maxC)
For r = 1 To maxR
ln = Split(arr(nextR), vbTab)
For c = 1 To UBound(ln) + 1
rng(r, c) = ln(c - 1)
Next
nextR = nextR + 1: If nextR > ubArr Then Exit For
Next
ws.Range(ws.Cells(1, 1), ws.Cells(maxR, maxC)) = rng
Next
End With
Application.ScreenUpdating = True
Debug.Print "Time: " & Format(Timer - t, "#,###.000") & " sec" 'Time: 64.966 sec
End Sub
Before (CSV file)
After

Create multiple text files for selected data on excel using vba scripting in single click

I am using the code below to generate the single file for selected range and considering the first cell in the selected range as file name. Please find the image below for more details[This image shows the selected range,Consider K column(Firstline) and N Column( Lastline) to be in one file and other set of 1st and last line in other file ]this image shows the print file for a single file this is the way m currently using for generating files.I need to create more 30k files so please help me to create more files in single click considering the first and last line as header and footer for the file
Private Sub CommandButton1_Click()
Dim myFile As String, rng As Range, cellValue As Variant, i As Integer, j As Integer, path As String, filename, filename2 As String
path = "D:\Watchlist-Files\"
filename = Selection.Cells(1, 1).Value
filename2 = Left(Mid(filename, 32, 99), Len(Mid(filename, 32, 99)) - 2)
myFile = path & filename2
Set rng = Selection
Open myFile For Output As #1
For i = 1 To rng.Rows.Count
For j = 1 To rng.Columns.Count
cellValue = rng.Cells(i, j).Value
If j = rng.Columns.Count Then
Print #1, cellValue
Else
Print #1, cellValue,
End If
Next j
Next i
Close #1
End Sub
The code below is using a Loop that scans rows in a range that consists of Columns K:N (according to your attached screen-shots).
Assumptions made: your FirstLine is in Column K, and it's the marker of the start position of copying the first cell in the first row.
Your LastLine is in Column N, and it's the marker of the last cell to copy, this is why I am closing the file once it is found.
Edit 1: added a Msgbox to allow the user selection of exporting the entire range or not. In case the user selected NO, then a second InputBox appears that allows the user to enter manually the last row number to export.
Option Explicit
Public Sub CommandButton1_Click()
Dim myFile As String
Dim rng As Range
Dim cellValue As Variant
Dim i As Long
Dim j As Long
Dim LastRow As Long
Dim path As String
Dim filename As String
Dim response As Boolean
path = "D:\Watchlist-Files\"
response = MsgBox("Do you want to Export the entire Range ? ", vbYesNo)
' Export the entire Range
If response = vbYes Then
LastRow = Cells(Rows.Count, "N").End(xlUp).Row
Else ' enter in the inputbox the last row number you want to export
LastRow = InputBox("Enter Last Row Number you wsnt to Export")
End If
Set rng = Range("K2:N" & LastRow)
For i = 2 To LastRow
' Column K holds the file name
If Cells(i, 11) <> "" Then
filename = Left(Mid(Cells(i, 11).Value, 32, 99), Len(Mid(Cells(i, 11).Value, 32, 99)) - 2)
myFile = path & filename
Open myFile For Output As #1
End If
For j = 1 To rng.Columns.Count
cellValue = Cells(i, 10 + j).Value
If j = rng.Columns.Count Then
Print #1, cellValue
' found LastLine >> close the file
If Not cellValue = "" Then
Close #1
End If
Else
Print #1, cellValue,
End If
Next j
Next i
End Sub
Edit 2: Added new code below (to keep the first option valid). The user needs to confirm that every selection he makes start and ends with FirstLine and LastLine , there is no error handling.
Option Explicit Section
Option Explicit
Dim filename As String
Dim path As String
Dim myFile As String
Dim rng As Range
Dim j As Long
Public Sub CommandButton1_Click
Public Sub CommandButton1_Click()
Dim lastRow As Long
Dim Sel_Range As Long
Dim response As Boolean
Dim rowStart() As Long
Dim rowFinish() As Long
path = "D:\Watchlist-Files\"
response = MsgBox("Do you want to Export only the Selected Range ? ", vbYesNo)
If response = True Then
Set rng = Selection
ReDim rowStart(1 To Selection.Areas.Count)
ReDim rowFinish(1 To Selection.Areas.Count)
For Sel_Range = 1 To Selection.Areas.Count
rowStart(Sel_Range) = Selection.Areas(Sel_Range).Row
rowFinish(Sel_Range) = Selection.Areas(Sel_Range).Row + Selection.Areas(Sel_Range).Rows.Count - 1
Call CreateTextFiles(rowStart(Sel_Range), rowFinish(Sel_Range))
Next Sel_Range
Else ' export the entire Range in Columns K:N
lastRow = Cells(Rows.Count, "N").End(xlUp).Row
Set rng = Range("K2:N" & lastRow)
Call CreateTextFiles(2, lastRow)
End If
Sub CreateTextFiles(Sel_StartRow As Long, Sel_FinishRow As Long) - new routine to allow handling of multiple Ranges selection
Sub CreateTextFiles(Sel_StartRow As Long, Sel_FinishRow As Long)
Dim i As Long
Dim cellValue As Variant
For i = Sel_StartRow To Sel_FinishRow
' Column K holds the file name
If Cells(i, 11) <> "" Then
filename = Left(Mid(Cells(i, 11).Value, 32, 99), Len(Mid(Cells(i, 11).Value, 32, 99)) - 2)
myFile = path & filename
Open myFile For Output As #1
End If
For j = 1 To rng.Columns.Count
cellValue = Cells(i, 10 + j).Value
If j = rng.Columns.Count Then
Print #1, cellValue
' found LastLine >> close the file
If Not cellValue = "" Then
Close #1
End If
Else
Print #1, cellValue,
End If
Next j
Next i
End Sub

Split function vba

I am currently attempting to take user input and split each bit of input using a comma. Currently I am trying to use -
includer = CStr(InputBox("Do you have any inclusions? Separate words with commas"))
inclusion = Split(includer, ",", , vbTextCompare)
with no luck.
It keeps throwing a 'Type Mismatch' error.
The full code I am attempting to use, for anyone that is interested, is-
Option Compare Text
Public Sub Textchecker()
'
' Textchecker
'
' Keyboard Shortcut: Ctrl+h
'
Dim Continue As Long
Dim findWhat As String
Dim LastLine As Long
Dim toCopy As Boolean
Dim cell As Range
Dim item As Long
Dim j As Long
Dim x As Long
Dim sheetIndex As Long
Dim inclusion() As String
sheetIndex = 2
Continue = vbYes
Do While Continue = vbYes
findWhat = CStr(InputBox("What word would you like to search for today?"))
includer = CStr(InputBox("Do you have any inclusions? Separate words with commas"))
inclusion = Split(includer, ",", , vbTextCompare)
LastLine = ActiveSheet.UsedRange.Rows.Count
If findWhat = "" Then Exit Sub
j = 1
For item = 1 To LastLine
For Each cell In Range("BY1").Offset(item - 1, 0)
If InStr(cell.Text, findWhat) <> 0 And InStr(cell.Text, inclusion(x)) <> 0 Then
toCopy = True
End If
Next
If toCopy = True Then
Sheets(sheetIndex).Name = UCase(findWhat) + "+" + LCase(inclusion(x))
Rows(item).Copy Destination:=Sheets(sheetIndex).Rows(j)
j = j + 1
End If
toCopy = False
Next item
sheetIndex = sheetIndex + 1
Continue = MsgBox(((j - 1) & " results were copied, do you have more keywords to enter?"), vbYesNo + vbQuestion)
Loop
End Sub
Change
Dim inclusion As String
to
Dim inclusion() As String 'recommended in my opinion
or
Dim inclusion As variant
Edit
I see your use of inclusion later in the code. It looks like you need to iterate over your new array.
dim x as long 'put this at the top, rename as you'd like.
for x = lbound(inclusion) to ubound(inclusion)
'do stuff with inclusion(x), i other code here before but I'm not sure that it was right anymore.
next
Edit 2
For item = 1 To LastLine
If UBound(insulation) >= 0 Then
'write procedure for when inclusion are present
Else
'write 2nd procedure for when inclusions are not present
End If
Next item

How to Import CSV to Excel with VBA

I Have a Red Lion Data station that records temperatures from about 25 ovens and the data is stored on a network in CSV files. I would like to import this data into an Excel file once every two minutes, but only import the changes after the initial import. After the import, the VBA must release the CSV file for the 2 minutes so that it can be updated by the data station. I have searched the web, this site and the closest thing I have found is the following code. This code looks for changes but it does not import the file. any help would be appreciated.
Dim NextTime As Date
Function LastModTime(FileSpec As String) As Date
'Returns the date-time the file specified by FileSpec (path string) was last modified
Dim fs, f, s
Set fs = CreateObject("Scripting.FileSystemObject")
Set f = fs.GetFile(FileSpec)
LastModTime = f.DateLastModified
End Function
Sub Check4Changes()
'Checks the file FilePath for changes every 60 seconds
'If file has changed, pops up a message box. Stores the
'last modified time in cell M1 of Sheet1
ChDir "Q:\Manufacturing\Equipment\DispatchLogs\logs\7-DES"
Const FilePath As String = "Q:\Manufacturing\Equipment\DispatchLogs\logs\7-DES\*.csv"
Dim LastMod As Date
On Error GoTo ReSchedule
LastMod = LastModTime(FilePath)
With Worksheets("Sheet1").Range("C1")
If IsEmpty(.Value) Then
.Value = LastMod
GoTo ReSchedule
ElseIf .Value < LastMod Then
.Value = LastMod
MsgBox FilePath & " updated.", vbInformation, "Check4Changes"
End If
End With
ReSchedule:
'Reschedule this same routine to run in one minute.
NextTime = Now + 2 / 1440
Application.StatusBar = "Next check at " & NextTime
Application.OnTime NextTime, "Check4Changes"
End Sub
Sub CancelChecking()
Application.OnTime NextTime, "Check4Changes", Schedule:=False
Application.StatusBar = False
End Sub
I have written some code which will give you the basic idea
Sub Main()
Dim Wbk_CSV As Excel.Workbook
Dim Excel_Wbk As Excel.Workbook
Dim Var_WholeCSVData As Variant
Dim Var_ExcelData As Variant
Dim Var_ToUpdate As Variant
Dim NumOfRows As Long
Dim Last_Row As Long
Set Wbk_CSV = Workbooks.Open("PathWithFileName")
Wbk_CSV.Sheets(1).Activate
Last_Row = ActiveSheet.Cells.SpecialCells(xlCellTypeLastCell).Row
'Taking whole data in a variant
'Change the range as per the data in csv file
Var_WholeCSVData = Wbk_CSV.Sheets(1).Range("A2:D" & Last_Row).Value 'Considering first row as header row and there are 4 columns
'After taking whole data in varinat close csv file without saving
Wbk_CSV.Close savechanges:=False
Set Wbk_CSV = Nothing
'Now open excel file in which data will be updated
Set Excel_Wbk = Workbooks.Open("PathWithFileName")
Excel_Wbk.Sheets(1).Activate
Last_Row = ActiveSheet.Cells.SpecialCells(xlCellTypeLastCell).Row
Var_ExcelData = Excel_Wbk.Sheets(1).Range("A2:D" & Last_Row).Value 'Considering first row as header row
NumOfRows = 0
'This function will return count of updated rows and data to update
Var_ToUpdate = Delete_Duplicates(Var_WholeCSVData, Var_ExcelData, NumOfRows)
Excel_Wbk.Sheets(1).Activate
'paste data
If NumOfRows > 0 Then
ActiveSheet.Range("A" & Last_Row + 1 & ":D" & Last_Row + NumOfRows).Value = Var_ToUpdate
End If
Excel_Wbk.Close savechanges:=True
Set Excel_Wbk = Nothing
'result
MsgBox ("Number of rows imported: " & NumOfRows)
End Sub
Function Delete_Duplicates(Var_FromCSV As Variant, Var_FromExcel As Variant, ByRef NumberOfRowToupdate As Long) As Variant
'using dictinpary objects
Dim dict_Duplicates As Object
Dim i_AddToDict, i, j As Long
Dim Str_value As String
Dim Var_Temp As Variant
Dim lng_temp As Long
Set dict_Duplicates = CreateObject("Scripting.Dictionary")
ReDim Var_Temp(1 To UBound(Var_FromCSV, 1), 1 To UBound(Var_FromCSV, 2))
'Add excel data to dict. by concatenating
'All unique values will be added
For i_AddToDict = 1 To UBound(Var_FromCSV)
Str_value = CStr(Var_FromExcel(i_AddToDict, 1) & Var_FromExcel(i_AddToDict, 2) & Var_FromExcel(i_AddToDict, 3) & Var_FromExcel(i_AddToDict, 4))
If dict_Duplicates.exists(Str_value) Then
'do nothing
Else
dict_Duplicates.Add Str_value, 1
End If
Next i_AddToDict
'looking for values which are not available in excel file
For i = 1 To UBound(Var_FromCSV)
Str_value = CStr(Var_FromCSV(i_AddToDict, 1) & Var_FromCSV(i_AddToDict, 2) & Var_FromCSV(i_AddToDict, 3) & Var_FromCSV(i_AddToDict, 4))
If dict_Duplicates.exists(Str_value) Then
'do nothing
Else
'storing values in a variant
For j = 1 To 4
Var_Temp(lng_temp, j) = Var_FromCSV(i, j)
Next j
lng_temp = lng_temp + 1
dict_Duplicates.Add Str_value, 1
End If
Next i
NumberOfRowToupdate = lng_temp - 1
Delete_Duplicates = Var_Temp
End Function