Create a loop until all cells have been used by script - vba

I don't really know how to program but I have compiled a few scripts to achieve nearly what I want, but I have failed at the last step.
The script opens a .txt file from a file directory in, cell B2, sheet 2, and copies its contents into excel (as well as a notepad which I don't care about).
However, I have 120 file directories I want to do this for. At the moment my script just takes the directory from cell B2, I have the rest of the 119 directories below it in the B column, I run the script and delete the row and repeat, which is a bit painstaking.
I would just like the script to run through all 120 files in the B column automatically. Any help appreciated!
Option Explicit
Sub ReadTxtFile()
Dim start As Date
start = Now
Dim oFSO As Object
Set oFSO = CreateObject("Scripting.FileSystemObject")
Dim oFS As Object
Dim filePath As String
'''''Assign the Workbook File Name along with its Path
filePath = Worksheets("Sheet2").Range("B2").Value
MsgBox Worksheets("Sheet2").Range("B2").Value
Dim arr(100000) As String
Dim i As Long
i = 0
If oFSO.FileExists(filePath) Then
On Error GoTo Err
Set oFS = oFSO.OpenTextFile(filePath)
Do While Not oFS.AtEndOfStream
arr(i) = oFS.ReadLine
i = i + 1
Loop
oFS.Close
Else
MsgBox "The file path is invalid.", vbCritical, vbNullString
Exit Sub
End If
For i = LBound(arr) To UBound(arr)
If InStr(1, arr(i), "Transmission", vbTextCompare) Then
'Declare variables for the new output file
Dim sOutputFileNameAndPath As String
Dim FN As Integer
sOutputFileNameAndPath = "C:\Users\nfraser\Documents\test\second.txt"
FN = FreeFile
'Open new output file
Open sOutputFileNameAndPath For Output As #FN
'While 'end of report' has not been found,
'keep looping to print out contents starting from 'report'
Do While InStr(1, arr(i), "Ancillary", vbTextCompare) = 0
Debug.Print i + 1, arr(i)
Range("A" & Range("A" & Rows.Count).End(xlUp).Row + 1) = i + 1
Range("B" & Range("B" & Rows.Count).End(xlUp).Row + 1) = arr(i)
'Print into new output file
Print #FN, i + 1 & " " & arr(i)
'increment count
i = i + 1
Loop
'Print out the 'end of report' line as well
Debug.Print i + 1, arr(i)
Range("A" & Range("A" & Rows.Count).End(xlUp).Row + 1) = i + 1
Range("B" & Range("B" & Rows.Count).End(xlUp).Row + 1) = arr(i)
'Print 'end of report' line into new output file as well
Print #FN, i + 1 & " " & arr(i)
'close the new output file
Close #FN
'exit the 'For..Next' structure since 'end of report' has been found
Exit For
End If
Next
Debug.Print DateDiff("s", start, Now)
Exit Sub
Err:
MsgBox "Error while reading the file.", vbCritical, vbNullString
oFS.Close
Exit Sub
End Sub

You can add a for... each loop, looping through all cells in your current selection. Here's the pattern:
Dim cCell as Range
For Each cCell in Selection
'do stuff
Next cCell
Now, since you change selections throughout your code, you have to store the selection at the onset into another variable, e.g. originalSelection and then loop through the cells in originalSelection. Otherwise, your selection will change during execution.
Adapting it to your code, we end up with the following... Please note: I broke your code into two methods---ReadTxtFiles and copyTo; the ReadTxtFile() sub was getting way too long.
Option Explicit
Sub ReadTxtFiles()
Dim start As Date
start = Now
Dim oFS As Object
Dim inputFilePath As String
Dim outputFilePath As String
Dim outputDirectory As String
outputDirectory = "C:\Users\nfraser\Documents\test\"
'''''Assign the Workbook File Name along with its Path
Dim originalSelection As Range
Dim cCell As Range
Dim i As Integer
Set originalSelection = Selection
For Each cCell In originalSelection
inputFilePath = cCell.Value
outputFilePath = outputDirectory & i & ".txt"
copyTo inputFilePath, outputFilePath
Next cCell
Debug.Print DateDiff("s", start, Now)
End Sub
Sub copyTo(inputPath As String, outputPath As String)
Dim arr(100000) As String
Dim i As Long
Dim oFSO As Object
Set oFSO = CreateObject("Scripting.FileSystemObject") 'late binding
Dim oFS As Object
i = 0
If oFSO.FileExists(inputPath) Then
On Error GoTo Err 'ensure oFS gets closed
Set oFS = oFSO.OpenTextFile(inputPath)
'read file contents into array
Do While Not oFS.AtEndOfStream
arr(i) = oFS.ReadLine
i = i + 1
Loop
'close
oFS.Close
Else 'file didn't exist
MsgBox "The file path is invalid.", vbCritical, vbNullString
Exit Sub
End If
For i = LBound(arr) To UBound(arr)
If InStr(1, arr(i), "Transmission", vbTextCompare) Then
'Declare variables for the new output file
Dim FN As Integer
FN = FreeFile
'Open new output file
Open outputPath For Output As #FN
'While 'end of report' has not been found,
'keep looping to print out contents starting from 'report'
Do While InStr(1, arr(i), "Ancillary", vbTextCompare) = 0
Debug.Print i + 1, arr(i)
Range("A" & Range("A" & Rows.Count).End(xlUp).Row + 1) = i + 1
Range("B" & Range("B" & Rows.Count).End(xlUp).Row + 1) = arr(i)
'Print into new output file
Print #FN, i + 1 & " " & arr(i)
'increment count
i = i + 1
Loop
'Print out the 'end of report' line as well
Debug.Print i + 1, arr(i)
Range("A" & Range("A" & Rows.Count).End(xlUp).Row + 1) = i + 1
Range("B" & Range("B" & Rows.Count).End(xlUp).Row + 1) = arr(i)
'Print 'end of report' line into new output file as well
Print #FN, i + 1 & " " & arr(i)
'close the new output file
Close #FN
'exit the 'For..Next' structure since 'end of report' has been found
Exit For
End If
Next
Exit Sub
Err:
MsgBox "Error while reading the file.", vbCritical, vbNullString
oFS.Close
Exit Sub
End Sub

For a quick action, Try this:
Change this line:
filePath = Worksheets("Sheet2").Range("B2").Value
Into a loop
Dim v As Variant, filepath As String
For Each v In Worksheets("Sheet2").Columns("B").SpecialCells(xlCellTypeConstants)
filepath = v.Value
debug.Print filePath
.... ' remainder of your code
.. then go to the Next line and write another Next line after it.

Related

Output in a different workbook

I've created a tool and the below macro copies all .csv files into a excel sheet. I want the data to be copied to the "Consol.xlsx" file that I created. The current code copies the data in the tool not the "Consol.xlsx" file. I am unable to update the code so that the data gets copied correctly.
Below is my code:
Sub Button_click2()
Call AddNew
Call ImportCSVsWithReference
End Sub
Sub AddNew()
Application.DisplayAlerts = False
Dim thisWb As Workbook
Set thisWb = ActiveWorkbook
Workbooks.Add
ActiveWorkbook.SaveAs Filename:=thisWb.path & "\Consol.xlsx"
Application.DisplayAlerts = True
End Sub
Sub ImportCSV()
Dim strSourcePath As String
Dim strDestPath As String
Dim strFile As String
Dim strData As String
Dim x As Variant
Dim Cnt As Long
Dim r As Long
Dim c As Long
Application.ScreenUpdating = False
'Change the path to the source folder accordingly
strSourcePath = Application.ActiveWorkbook.path
If Right(strSourcePath, 1) <> "\" Then strSourcePath = strSourcePath & "\"
'Change the path to the destination folder accordingly
strDestPath = Application.ActiveWorkbook.path
If Right(strDestPath, 1) <> "\" Then strDestPath = strDestPath & "\"
strFile = Dir(strSourcePath & "*.csv")
Do While Len(strFile) > 0
Cnt = Cnt + 1
r = Cells(Rows.count, "A").End(xlUp).Row + 1
Open strSourcePath & strFile For Input As #1
Do Until EOF(1)
Line Input #1, strData
x = Split(strData, ",")
For c = 0 To UBound(x)
Cells(r, c + 1).Value = Trim(x(c))
Next c
r = r + 1
Loop
Close #1
Name strSourcePath & strFile As strDestPath & strFile
strFile = Dir
Loop
Application.ScreenUpdating = True
If Cnt = 0 Then _
MsgBox "No CSV files were found...", vbExclamation
End Sub
Well it looks like you've got both of the pieces there. Your first subroutine saves a blank workbook called consol.xlsx.
Then, your second subroutine loops through the directory, opens each csv file, and copes it to some unspecified range.
What I would insert before your loop is:
Set wbkConsol = Workbooks.Open(thisWorkbook.path & "\Consol.xlsx")
Then, during your loop over the CSV files:
strFile = Dir(strSourcePath & "*.csv")
Do While Len(strFile) > 0
Cnt = Cnt + 1
r = Cells(Rows.count, "A").End(xlUp).Row + 1
Open strSourcePath & strFile For Input As #1
Do Until EOF(1)
Line Input #1, strData
' Set wshAdd = wbkConsol.Worksheets.Add() ' New ws in wbk
' wshAdd.Name = left(strFile, 31) ' First 31-chars of filename.
x = Split(strData, ",")
For c = 0 To UBound(x)
wshAdd.Cells(r, c + 1).Value = Trim(x(c))
Next c
r = r + 1
Loop
Close #1
Name strSourcePath & strFile As strDestPath & strFile
strFile = Dir()
Loop
As an added note: you could pass your workbook from your first sub to the second sub, by reference. That way, you won't have to open it up again. This would be by combining the button click into just a single command.
Sub1()
wbkConsol = workbooks.Add
Call sub2(wbkConsol)
End sub

not able to copy data from PDF file

I am able to open pdf doc from attachments from mail. Now I want to copy its content. kindly provide code to select all and copy. Below is the code and I have mentioned where I need help.
I am able to open pdf doc from attachments from mail. Now I want to copy its content. kindly provide code to select all and copy. Below is the code and I have mentioned where I need help.
Sub ExtractFirstUnreadEmailDetails()
Dim oOlAp As Object, oOlns As Object, oOlInb As Object
Dim oOlItm As Object
Dim objAtt As Outlook.Attachment
'On Error Resume Next
'~~> Outlook Variables for email
Dim eSender As String, dtRecvd As String, dtSent As String
Dim sSubj As String, sMsg As String
Dim AttchType As String
'~~> Get Outlook instance
Set oOlAp = GetObject(, "Outlook.application")
Set oOlns = oOlAp.GetNamespace("MAPI")
Set oOlInb = oOlns.GetDefaultFolder(olFolderInbox)
'~~> Check if there are any actual unread emails 'apurv
'If oOlInb.Items.Restrict("[UnRead] = True").Count = 0 Then 'apurv
' MsgBox "NO Unread Email In Inbox" 'apurv
' Exit Sub 'apurv
' End If 'apurv
'~~> Store the relevant info in the variables
'For Each oOlItm In oOlInb.Items.Restrict("[UnRead] = True")
For Each oOlItm In oOlInb.Items
eSender = oOlItm.SenderEmailAddress
dtRecvd = oOlItm.ReceivedTime
dtSent = oOlItm.CreationTime
sSubj = oOlItm.Subject
sMsg = oOlItm.Body
ToAddress = oOlItm.To
i = ThisWorkbook.ActiveSheet.Cells(Rows.Count, 2).End(xlUp).Row
Range("c" & (i + 1)).Value = eSender
Range("B" & (i + 1)).Value = dtRecvd
'range("c"&(i+1)).Value=dtSent
Range("E" & (i + 1)).Value = sSubj
Range("F" & (i + 1)).Value = sMsg
Range("D" & (i + 1)).Value = ToAddress
If oOlItm.Attachments.Count <> 0 Then
temp = ""
For Each oOlAtch In oOlItm.Attachments
temp = temp & "//" & oOlAtch.Filename
Next
Range("G" & (i + 1)).Value = temp
End If
If oOlItm.Attachments.Count <> 0 Then
temp = ""
For Each oOlAtch In oOlItm.Attachments
If InStr(1, UCase(oOlAtch.Filename), "PDF", vbTextCompare) > 1 Then
oOlAtch.SaveAsFile "D:\Users\apawar\Desktop\Attachments\" & oOlAtch.Filename
Shell "Explorer.exe /e,D:\Users\apawar\Desktop\Attachments\" & oOlAtch.Filename, vbNormalFocus
'NEED HELP HERE......Need to copy all data from pdf doc from 1st page
End If
Next
Range("G" & (i + 1)).Value = temp
End If
Next
MsgBox ("Down loaded successufully")
End Sub
You should probably get Acrobat, and this will be much easier. Or, convert the PDF into a text file, simply by saving it, and import the text into Excel.

Open text file only once in excel vba

I have below code which prints text from a column but open a text file many times instead of once. Please let me know what is the wrong.
When I run sub in Visual Basic debug mode, it open text file only once. But I am calling this macro after another macro and that time it is opening (same) text file many times.
Sub createdevtest()
Dim filename As String, lineText As String
Dim data As Range
Dim myrng As Range, i, j
' filename = ThisWorkbook.Path & "\textfile-" & Format(Now, "ddmmyy-hhmmss") & ".txt"
filename = ThisWorkbook.Path & "\devtest" & ".txt"
Open filename For Output As #1
Dim LastRow As Long
'Find the last non-blank cell in column A(1)
LastRow = Cells(Rows.count, 1).End(xlUp).Row
Range("B4:B" & LastRow).Select
Set myrng = Selection
For i = 1 To myrng.Rows.count
For j = 1 To myrng.Columns.count
lineText = IIf(j = 1, "", lineText & ",") & myrng.Cells(i, j)
Next j
Print #1, lineText
Next i
Close #1
Range("B4").Select
' open devtest
'Shell "explorer.exe" & " " & ThisWorkbook.Path, vbNormalFocus
filename = Shell("Notepad.exe " & filename, vbNormalFocus)
End Sub
Thanks #Luuklag. I had tried to figure out on my own but no success. After your comment, just went thru code again and got clue.
Below is the correct code where I have called one of the macro (devtest1) which contains above text file creation macro (createdevtest). Before correction I was calling macro in function instead of Sub, so it was looping again and opening txt file many times.
' macro to select folder and list files
Sub GetFileNames_devtest()
Set Folder = Application.FileDialog(msoFileDialogFolderPicker)
If Folder.Show <> -1 Then Exit Sub
xDir = Folder.SelectedItems(1)
Call ListFilesInFolder(xDir, True)
' call devtest: corrected to call macro at right place
devtest1
End Sub
Sub ListFilesInFolder(ByVal xFolderName As String, ByVal xIsSubfolders As Boolean)
Dim xFileSystemObject As Object
Dim xFolder As Object
Dim xSubFolder As Object
Dim xFile As Object
Dim rowIndex As Long
Set xFileSystemObject = CreateObject("Scripting.FileSystemObject")
Set xFolder = xFileSystemObject.GetFolder(xFolderName)
rowIndex = Application.ActiveSheet.Range("A65536").End(xlUp).Row + 1
For Each xFile In xFolder.Files
Application.ActiveSheet.Cells(rowIndex, 1).Formula = xFile.Name
rowIndex = rowIndex + 1
Next xFile
If xIsSubfolders Then
For Each xSubFolder In xFolder.SubFolders
ListFilesInFolder xSubFolder.Path, True
Next xSubFolder
End If
Set xFile = Nothing
Set xFolder = Nothing
Set xFileSystemObject = Nothing
'' Was calling wrongly macro here
End Sub
Function GetFileOwner(ByVal xPath As String, ByVal xName As String)
Dim xFolder As Object
Dim xFolderItem As Object
Dim xShell As Object
xName = StrConv(xName, vbUnicode)
xPath = StrConv(xPath, vbUnicode)
Set xShell = CreateObject("Shell.Application")
Set xFolder = xShell.Namespace(StrConv(xPath, vbFromUnicode))
If Not xFolder Is Nothing Then
Set xFolderItem = xFolder.ParseName(StrConv(xName, vbFromUnicode))
End If
If Not xFolderItem Is Nothing Then
GetFileOwner = xFolder.GetDetailsOf(xFolderItem, 8)
Else
GetFileOwner = ""
End If
Set xShell = Nothing
Set xFolder = Nothing
Set xFolderItem = Nothing
End Function
End Function

Injecting Code to format all columns as text to retain leading zeros from CSVs

So here is 1 part of a 3 part macro that lets you browse to a folder and consolidate/transpose/retain header of a bunch of .csv files. The problem we have is where to inject some code so that routing and account numbers are formatted as text and retain their leading zeros. If the easiest solution is to just format the entire sheet as text, that would work for us...whatever it takes without having to go into specifics since this info wont always be in the same column.
Thanks in advance!
Option Explicit
'Set a public constant variable
Public Const DNL As String = vbNewLine & vbNewLine
Sub ImportData()
'Declare all variables
Dim wb As Workbook, ws As Worksheet
Dim wbX As Workbook, wsX As Worksheet
Dim i As Long, iRow As Long, iFileNum As Long, sMsg As String
Dim vFolder As Variant, sSubFolder As String, sFileName As String
Dim bOpen As Boolean
'Turn off some application-level events to improve code efficiency
Call TOGGLEEVENTS(False)
'Have the user choose the folder
vFolder = BrowseForFolder()
'Exit if nothing was chosen, variable will be False
If vFolder = False Then Exit Sub
'Check if this is what the user wants to do, confirm with a message box, exit if no
sMsg = "Are you sure you want to import data from this folder:"
sMsg = sMsg & DNL & vFolder
If MsgBox(sMsg, vbYesNo + vbDefaultButton2, "ARE YOU SURE?") <> vbYes Then Exit Sub
'Set sub-folder as variable for save name at end of routine
sSubFolder = Right(vFolder, Len(vFolder) - InStrRev(vFolder, Application.PathSeparator))
'Set destination file with one worksheet
Set wb = Workbooks.Add(xlWBATWorksheet)
Set ws = wb.Sheets(1)
'This will be the row to start data on, to incriment in loop
iRow = 2
'Loop through files in folder
sFileName = Dir$(vFolder & "\")
Do Until sFileName = ""
'Check that the file pattern matches what you want, i.e. 12.16.00.xls
If sFileName Like "*.csv" Then '### set file extension here
'Check to see if the file is open
'If file is open, set as variable, if not, open and set as variable
If ISWBOPEN(sFileName) = True Then
Set wbX = Workbooks(sFileName)
bOpen = True
Else
Set wbX = Workbooks.Open(vFolder & "\" & sFileName)
bOpen = False
End If
'Set first sheet in target workbok as worksheet variable, from which to mine data
Set wsX = wbX.Sheets(1)
'Get last row from column A (range for copy/pasting)
i = wsX.Cells(wsX.Rows.Count, 1).End(xlUp).Row
'Check if a file has been added, if not add headers (frequency)
If iFileNum = 0 Then
ws.Range("B1", ws.Cells(1, i + 1)).Value = Application.Transpose(wsX.Range("A1:A" & i))
End If
'Add data
ws.Range("B" & iRow, ws.Cells(iRow, i + 1)).Value = Application.Transpose(wsX.Range("B1:B" & i))
'Add file name to column A
ws.Range("A" & iRow).Value = "'" & Left$(sFileName, Len(sFileName) - 4)
'Incriment variable values
iRow = iRow + 1
iFileNum = iFileNum + 1
'If file was closed to start with, clean up and close it
If bOpen = False Then wbX.Close SaveChanges:=False
End If
'Get next file name
sFileName = Dir$()
Loop
'Check if file name to save exists
If Dir$(vFolder & "\" & sSubFolder & ".xls", vbNormal) = "" Then
wb.SaveAs vFolder & "\" & sSubFolder & ".xls"
MsgBox "Complete!", vbOKOnly
Else
MsgBox "File already exists! File is NOT saved!", vbInformation, "COMPLETE!"
End If
'Reset events back to application defaults
Call TOGGLEEVENTS(True)
End Sub

Run-time error '1004' Method 'Save' of object '_Workbook' failed

I got this error while running an VBA application. I think this error is related to the following line in my code
ActiveWorkbook.Save
This is the whole code.
LDate = Date
LDate = Mid(LDate, 4, 2)
If LDate > 8 Then
Sheets("a").Cells(13, "H").Value = Sheets("a").Cells(13, "H").Value + 1000
Else
Sheets("a").Cells(13, "H").Value = Sheets("a").Cells(13, "H").Value + 1
End If
ActiveWorkbook.Save
Can someone explain the cause of this error and how I can tackle it.
Please read below comments.
This is the subroutine that is getting executed when the first button is clicked.
Sub import()
Dim Filt As String
Dim FilterIndex As Integer
Dim Title As String
Dim FileName As Variant
Dim finalrow As Integer
Dim alldata As String
Dim temp As String
Dim oFSO As New FileSystemObject
Dim oFS As TextStream
'Filt = "Cst Files (*.txt),*.txt"
'Title = "Select a cst File to Import"
'FileName = Application.GetOpenFilename(FileFilter:=Filt, Title:=Title)
'If FileName = False Then
'MsgBox "No File Was Selected"
'Exit Sub
'End If
'Call TestReference
' Open the file dialog
Set diaFolder = Application.FileDialog(msoFileDialogFolderPicker)
diaFolder.AllowMultiSelect = False
diaFolder.Show
If diaFolder.SelectedItems.Count <> 0 Then
folderpath = diaFolder.SelectedItems(1)
folderpath = folderpath & "\"
'MsgBox diaFolder.SelectedItems(1)
Set diaFolder = Nothing
'RefreshSheet
On Error Resume Next
temp = folderpath & "*.txt"
sFile = Dir(temp)
Do Until sFile = ""
inputRow = Sheets("RawData").Range("A" & Rows.Count).End(xlUp).Row + 1
FileName = folderpath & sFile
Set oFS = oFSO.OpenTextFile(FileName)
Dim content As String
content = oFS.ReadAll
content = Mid(content, 4, Len(content) - 3)
With Sheets("RawData").Range("A" & inputRow)
.NumberFormat = "#"
.Value = content
End With
oFS.Close
Set oFS = Nothing
alldata = ""
finalrow = Sheets("RawData").Cells(Rows.Count, 1).End(xlUp).Row
Sheets("RawData").Activate
For i = inputRow To finalrow
alldata = alldata & Cells(i, "A").Value & " "
Cells(i, "A").Value = ""
Next i
Cells(inputRow, "B").Value = alldata
temp = StrReverse(FileName)
temp = Left(temp, InStr(1, temp, "\") - 1)
temp = StrReverse(temp)
temp = Left(temp, InStr(1, temp, ".") - 1)
Cells(inputRow, "A").Value = temp
Sheets("RawData").Cells(inputRow, "A").NumberFormat = "#"
sFile = Dir()
Loop
Else
MsgBox ("No Folder Selected")
End If
End Sub
How to make this code stop accessing the worksheet after executing this macro?
Although I think you should seriously consider refactoring your code, you should begin by referencing the correct workbook called by the .Save() Method.
Workbooks("Insert_Workbook_Name_Here.xlsm").Save
Make sure that the workbook name and extension (.xlsm, .xls, .xlsx) match the file you are actually trying to save.
This error happened in a macro that I wrote as well. I have this code to close a dialogue box.
Private Sub CancelButton_Click()
Unload Me
ThisWorkbook.Save
End
End Sub
I received the same error because the workbook that was being loaded was from a "last saved" copy due to an update reboot that happened while the original was open. Not sure how to avoid that in the future but thought it might be helpful to someone.