Looping Through Txt Files using VBA - DIR() issue - excel

I have the following code where I am trying to modify some Txt files in a specific folder. I first want to check that the Loop works. However when I run the macro the code can only read the first file and then there is a runtime 5 error at strFileName = Dir(). I am not sure what the problem is. The only issue I can think of is that I am moving the code between two module sheets. The folder location is being saved in a txt box in Sheet 1 of an excel workbook.
Sub Txt_File_Loop()
Public TextFile As String
Dim FolderLocation As String
Dim strFielName As String
Dim SaveLocation As String
'Location is present in a Text box
FolderLocation = Sheets(1).FolderLocationTXTBX.Text
strFileName = Dir(FolderLocation & " \ * ")
Do Until strFileName = ""
TextFile = FolderLocation & "\" & strFileName
Module2.Macro1
strFileName = Dir() 'ERROR is Here
Loop
End Sub
Sub Macro1()
Dim x As String
Open TextFile For Input As #1
Do Until EOF(1)
Line Input #1, textline
x = x & textline
Loop
Close #1
MsgBox x
End Sub

Have a look at these modifications. They seem to correct several things and run through well.
Option Explicit
Sub Txt_File_Loop()
Dim FolderLocation As String
Dim strFileName As String
Dim SaveLocation As String
'Location is present in a Text box
FolderLocation = Sheets(1).FolderLocationTXTBX.Text 'Environ("TMP")
strFileName = Dir(FolderLocation & "\*.txt")
Do Until strFileName = ""
Debug.Print FolderLocation & "\" & strFileName
Module2.Macro1 FolderLocation & "\" & strFileName
strFileName = Dir() 'ERROR is Here
Loop
End Sub
Sub Macro1(sFPFN As String)
Dim x As String, textline As String
Debug.Print sFPFN
Open sFPFN For Input As #1
Do Until EOF(1)
Line Input #1, textline
x = x & textline
Loop
Close #1
MsgBox x
End Sub
I passed the folder and filename name across as a string-type parameter. Also, I don't know why you had the extra spaces in (FolderLocation & " \ * " ; I tightened that up. There were a few misspellings and undeclared variables; these can be avoided with Option Explicit¹ at the top of the module code sheet. Get into the practise of standard indentation with your code. It certainly improves readability if nothing else.
¹ Setting Require Variable Declaration within the VBE's Tools ► Options ► Editor property page will put the Option Explicit statement at the top of each newly created code sheet. This will avoid silly coding mistakes like misspellings as well as influencing you to use the correct variable type in the variable declaration. Variables created on-the-fly without declaration are all of the variant/object type. Using Option Explicit is widely considered 'best practice'.

Related

VBA opening a file with partial name

I am trying to open a file which will be updated periodically. The current name is "GDE Portfolio Characteristics 12.31.2021" and the idea is to instruct the code to open it, no matter the date (i.e. the last 10 characters). I should only have one file in the folder with such a partial name.
The code I use is the following:
Workbooks.Open Filename:=ThisWorkbook.Path & "\Parametric GDE Portfolio Characteristics*.xlsx"
When running it, it seems it does not find the file. It works if I instead use the entire name of the file.
Newbie problem, but scratching my head in frustration!
Many thanks
There is no way to use a wildcard in the Open-statement. However, you can use the
Dir-command to get the real file name as it allows wildcards:
Dim fileName As String
fileName = Dir(ThisWorkbook.Path & "\Parametric GDE Portfolio Characteristics*.xlsx")
If fileName <> "" Then
Workbooks.Open Filename:=ThisWorkbook.Path & "\" & fileName
End If
Here is a more generic approach:
Sub OpenFiles()
Dim Files As Collection
Set Files = ListFiles(ThisWorkbook.Path, "Parametric GDE Portfolio Characteristics*.xlsx")
Dim Filename As Variant
For Each Filename In Files
Workbooks.Open Filename:=Filename
Next
End Sub
Function ListFiles(FolderName As String, SearchString As String) As Collection
Set ListFiles = New Collection
Dim Filename As String
Filename = Dir(FolderName & "\" & SearchString)
If Len(Filename) = 0 Then Exit Function
Do While Filename <> ""
ListFiles.Add Filename
Filename = Dir()
Loop
End Function

Why is VBA script adding double quotes at start/end of files

Hello Dear StackOverFlowers,
My question may be trival but I'm currently out of option to think of after searching all afternoon
Context: I have a excel worksheet with 120 rows or so that I need to use to create files with.
Data is structured as follow:
The A column contains destination file names
B column has the corresponding data that needsto be written in each file
Giving us the following general layout
data file layout
So, to get data from B column written in each A column named files, I wrote the followin VBScript snippet:
Option Explicit
Sub writeExportedMsgToXML()
' wrote that tiny script not to have to copy pate 117 messages by hand to have ops put them back on Q
Dim currentRow As Integer
' modify to match your data row start and end
For currentRow = 2 To 11
Dim messageID As String
Dim messageitSelf As String
messageID = Trim(ActiveSheet.Range("A" & currentRow))
messageitSelf = ActiveSheet.Range("B" & currentRow)
Dim subDirectory As String
subDirectory = "xmls"
Dim filePath As String
filePath = ActiveWorkbook.Path & "\" & subDirectory & "\" & messageID & ".xml"
MsgBox (messageitSelf) ' for test purpose
Open filePath For Output As #1
Write #1, messageitSelf
Close #1
Next currentRow
End Sub
The script does mostly what it's intended for Except , and this is the source of my question today, it enclose the file content between double quotes as you can see below:
file content enclosed in double quotes
So, in a case where a file named F1.xml should just contain <foo><bar>Baz</bar></foo>
My script transform it as "<foo><bar>Baz</bar></foo>"
What I tried
Replacing file writing part with the following
Dim objStream
Set objStream = CreateObject("ADODB.Stream")
objStream.Charset = "UTF-8"
Dim subDirectory As String
subDirectory = "xmls"
Dim filePath As String
filePath = ActiveWorkbook.Path & "\" & subDirectory & "\" & messageID & ".xml"
objStream.Open
objStream.WriteText messageitSelf
objStream.SaveToFile filePath
objStream.Close
With same outcome
Any clues on what I'm missing/Doing wrong ?
Should I declare messageitSelf as a different type ?
Any help would be appreciated :)
Thank you
Write# statements surround strings with double quotes:
Unlike the Print # statement, the Write # statement inserts commas between items and quotation marks around strings as they are written to the file.
Use Print# instead:
Dim fn As Long
fn = VBA.FreeFile
Open filePath For Output As #fn
Print #fn, messageitSelf
Close #fn

Problems with Worksheetfunction.Match in a closed workbook. Cannot work out why no match is found

I'm writing a code to delete a log entry in a .csv file. The code starts with opening the .csv file, using Application.Match to return the row number, and then deleting that and closing the file again. The problems I'm experiencing are I get a type mismatch (my error handling is activated) OR (and here it gets weird) it works (a match is found, the row is deleted) but then the logfile is messed up - all data is one string in column a with either ";" or "," delimiters (this varies somehow, relevant note: I use Dutch language excel). Of course, this makes it impossible for the macro to find a match in any case.
I found that the type mismatch problems I'm experiencing will most likely be caused by the code not finding a match, and this is what I don't understand since I checked and doublechecked the input and the data in the logfile - by all means it simply should find a match. And sometimes it does find a match, deletes the row and messes up formatting. (NOTE: Mostly it does NOT find a match.)
I check data in the .csv file before running the macro. I have tried running the macro with the .csv file already opened. I have tried to Set the matchArray from outside the With. I have tried both sweet talking my laptop and a more aggressive approach, to no avail.
Sub DeleteRowFromFile(ByVal matchValue As String)
Dim filePath As String
Dim fileName As String
Dim fileType As String
Dim matchArray As Range
Dim rowToDelete As Variant
'Naming variables for flexibility
filePath = "C:\Users\Maxim\Documents\Log\"
fileName = "TestRegister"
fileType = ".csv"
Application.ScreenUpdating = False
Workbooks.Open (filePath & fileName & fileType)
With Workbooks(fileName).Worksheets(1)
Set matchArray = .Range("A:A") 'set range in the logfile
'Type mismatch here:
rowToDelete = Application.Match(matchValue, matchArray, 0)
If Not IsError(rowToDelete) Then
Rows(rowToDelete).Delete
Else:
MsgBox "Orderno. " & matchValue & " not found.", vbOKOnly + vbExclamation, "Error"
End If
End With
'Closing the log file
Workbooks(fileName).Close SaveChanges:=True
Application.ScreenUpdating = True
End Sub
Sub MatchAndDelete()
Dim matchValueRange As String
matchValueRange = ActiveWorkbook.Worksheets(1).Range("A1").Value
DeleteRowFromFile (matchValueRange)
End Sub
Footnote:
I'm a struggling enthusiast, I have a lot to learn. Sorry in advance if I have left out any crucial information for you to be of help, and thanks a lot for any and all help.
When you open or save a csv file using a VBA macro Excel will always use the standard (US English delimiters) while if you do the same via the user interface it will use the separators as defined in the Windows regional settings, which probably is ";" in your case.
You can check with .?application.International(xlListSeparator) in the immediate window of your VBEditor.
You can tell Excel to use a different separator, by e.g. adding sep=; as line 1 of your file. Hoever this entry is gone after opening the file. The following code - added before you open the csv file will add this:
Dim oFSo As Object
Dim oTxtFile As Object
Dim strData As String
Set oFSo = CreateObject("Scripting.FileSystemObject")
strData = oFSo.OpenTextFile(filePath & fileName & fileType, 1).ReadAll
Set oTxtFile = oFSo.OpenTextFile(filePath & fileName & fileType, 2)
oTxtFile.writeline "sep=;"
oTxtFile.writeline strData
oTxtFile.Close
You can save your changed file by using the Excel UserInterface Shortcuts via the Application.SendKeys thus achieving what you want:
Application.SendKeys ("^s") 'Save
Application.SendKeys ("^{F4}") 'Close
Dont run this code from the VBE Immeditate window as it will probabaly act on the wrong file!
The full code - just with an alternate way to make the requested change:
Sub DeleteRowFromFile(ByVal matchValue As String)
Dim filePath As String
Dim fileName As String
Dim fileType As String
Dim matchArray As Range
Dim rowToDelete As Variant
Dim oFSo As Object
Dim oTxtFile As Object
Dim strData As String
Dim content As Variant
Dim i As Long
'Naming variables for flexibility
filePath = "C:\Users\Maxim\Documents\Log\"
fileName = "TestRegister"
fileType = ".csv"
Application.ScreenUpdating = False
'Adding "sep =" ; as line 1 of the log file
Set oFSo = CreateObject("Scripting.FileSystemObject")
strData = oFSo.OpenTextFile(filePath & fileName & fileType, 1).ReadAll
Set oTxtFile = oFSo.OpenTextFile(filePath & fileName & fileType, 2)
oTxtFile.writeline "sep=;"
oTxtFile.writeline strData
oTxtFile.Close
'Open logfile
Workbooks.Open (filePath & fileName & fileType)
'Make your changes
With Workbooks(fileName).Worksheets(1)
content = .UsedRange.Value
For i = UBound(content, 1) To 1 Step -1
If content(i, 1) = matchValue Then
.Rows(i).Delete
End If
Next i
End With
'Closing the log file via Sendkeys using excel shortcuts
Application.SendKeys ("^s") 'Save
Application.SendKeys ("^{F4}") 'Close
Application.ScreenUpdating = True
I think that Match it is not required. Try this one.
Sub DeleteRowFromFile(ByVal matchValue As String)
Dim filePath As String
Dim fileName As String
Dim fileType As String
Dim matchArray As Range
Dim rowToDelete As Variant
'Naming variables for flexibility
filePath = "C:\Users\Maxim\Documents\Log\"
fileName = "TestRegister"
fileType = ".csv"
Application.ScreenUpdating = False
Workbooks.Open (filePath & fileName & fileType)
With Workbooks(fileName).Worksheets(1)
For i = .UsedRange.SpecialCells(xlCellTypeLastCell).Row To 1 Step -1
If .Cells(i, 1).Value2 = matchValue Then
.Cells(i, 1).EntireRow.Delete
End If
Next
End With
'Closing the log file
Workbooks(fileName & fileType).SaveAs Filename:= _
(filePath & fileName & fileType) _
, FileFormat:=xlCSVMSDOS, CreateBackup:=False 'Saving the file
Workbooks(fileName & fileType).Close 'Closing the file
Application.ScreenUpdating = True
End Sub
Hope it helps

Excel Macro saving file to the wrong directory

I have looked at quite a lot of similar questions, but none of them seem to work for my specific issue.
I have a macro that saves my file with a new name if it encounters a file with the same name.
What keeps happening is that it saves the original file to the correct folder, but then when it encounters the file name the next time I save it, the instanced file gets saved to the same folder as the template rather than the folder that they should go to.
In the example below, my template file is saved in the "M:\Excel\" directory.
It saves the first "TEST" file into the "M:\Excel\SavedVersions\" directory since the file name doesn't exist yet.
Then when I run the macro again to have it automatically save an instanced version (ie - "TESTrev1"), it keeps saving the instanced versions to the "M:\Excel\" directory instead of saving it to the "SavedVersions" subfolder.
Not sure what needs to be changed or done differently to get the instanced versions to save to the correct folder.
Any help would be greatly appreciated!
Thanks in advance! :)
Sub TEST()
ActiveWorkbook.Save
ActiveWorkbook.SaveAs Filename:= _
GetNextAvailableName("M:\Excel\SavedVersions\TEST.xlsm")
End Sub
Function GetNextAvailableName(ByVal strPath As String) As String
With CreateObject("Scripting.FileSystemObject")
Dim strFolder As String, strBaseName As String, strExt As String, i As Long
strFolder = .GetParentFolderName("M:\Excel\SavedVersions\")
strBaseName = .GetBaseName("TEST")
strExt = .GetExtensionName(".xlsm")
Do While .FileExists(strPath)
i = i + 1
strPath = .BuildPath(strFolder, strBaseName & "rev" & i & "." & strExt)
Loop
End With
GetNextAvailableName = strPath
End Function
Your code was unnecessarily complex.
Try this simpler version.
Sub TEST()
ActiveWorkbook.Save
ActiveWorkbook.SaveAs fileName:= _
GetNextAvailableName("M:\Excel\SavedVersions\TEST.xlsm")
End Sub
Function GetNextAvailableName(ByVal strPath As String) As String
Dim i as Interger: i = 0
Do Until Len(Dir(strPath)) = 0
i = i + 1
strPath = "M:\Excel\SavedVersions\TESTrev" & i & ".xlsm"
Loop
GetNextAvailableName = strPath
End Function
Keep your code simple. If your path is constant then might as well define a variable for it so that it can be used whenever and whereever you want. This way if there is any change in the path, you have to make the change at only one place.
While saving the file, also specify the FileFormat parameter to avoid problems. You might want to read more about it HERE
Is this what you are trying?
Option Explicit
Const sPath As String = "M:\Excel\SavedVersions\"
Sub Sample()
Dim flName As String
flName = sPath & GetNextAvailableName()
ActiveWorkbook.Save
ActiveWorkbook.SaveAs Filename:=flName, _
FileFormat:=xlOpenXMLWorkbookMacroEnabled
End Sub
Function GetNextAvailableName() As String
Dim i As Integer: i = 1
Dim newFile As String
newFile = "TestRev" & i & ".xlsm"
Do Until Dir(sPath & newFile) = ""
i = i + 1
newFile = "TestRev" & i & ".xlsm"
Loop
GetNextAvailableName = newFile
End Function

How do I change multiple reference tags in XML based on spreadsheet values

I am a technical writer and not much of a coder, I have thousands of .xml files that combined create a book. I used a VBA script from this website to rename all of the files to fit within the new guidelines, now I need to go into the xml code and find all references to those links and replace them with the new file name.
I have an excel spreadsheet where in column A it has the old file name and in column B it has the new file name.
The tag looks like this:
<?iads.link docref="R381"?>
It needs to find "R381" in column A and replace it with "R01081-1-1520-237", the file name in the adjacent cell in column B.
The Tag needs to look like this:
<?iads.link docref="R01081-1-1520-237"?>
I tried using the code from the question How can I Find/Replace multiple strings in an xml file? but it did not work and I'm not even sure if that's the correct question to be asking
My current code looks lie this:
Option Explicit ' Use this !
Public Sub ReplaceXML(rFindReplaceRange As Range) ' Pass in the find-replace range
Dim sBuf As String
Dim sTemp As String
Dim iFileNum As Integer
Dim sFileName As String
Dim i As Long
' Edit as needed
sFileName = "C:\Users\s37739\Desktop\chap3"
iFileNum = FreeFile
Open sFileName For Input As iFileNum
Do Until EOF(iFileNum)
Line Input #iFileNum, sBuf
sTemp = sTemp & sBuf & vbCrLf
Loop
Close iFileNum
' Loop over the replacements
For i = 1 To rFindReplaceRange.Rows.Count
If rFindReplaceRange.Cells(i, 1) <> "" Then
sTemp = Replace(sTemp, rFindReplaceRange.Cells(i, 1), rFindReplaceRange(i, 2))
End If
Next i
' Save file
iFileNum = FreeFile
' Alter sFileName first to save to a different file e.g.
sFileName = "C:\Users\s37739\Desktop\chap3"
Open sFileName For Output As iFileNum
Print #iFileNum, sTemp
Close iFileNum
End Sub
Sub mike1()
End Sub
You are passing the file path when in fact you should be passing the fully qualified file name (file path and file name).
You need to edit those lines
' Edit as needed
sFileName = "C:\Users\s37739\Desktop\chap3"
'...
' Alter sFileName first to save to a different file e.g.
sFileName = "C:\Users\s37739\Desktop\chap3"
With
' Edit as needed
sFileName = "C:\Users\s37739\Desktop\chap3\yourfilename.xml"
'...
' Alter sFileName first to save to a different file e.g.
sFileName = "C:\Users\s37739\Desktop\chap3\yourNEWfilename.xml"
Also, remember to provide the correct Range when running the procedure.
Supposing your Range goes from "A1:B50" you can edit your mike1 sub as follows:
Sub mike1()
' Change range as desired
Call ReplaceXML(ThisWorkbook.Worksheets("YourSheetName").Range("A1:B50"))
End Sub
After that, all you need to do is run mike1 from the Immediate window.
Access using Alt+F11 for the VBA editor then View -> Immediate.
You should see a new window at the bottom of the screen. Just type mike1 in there and hit Enter
UPDATE:
Ideally, you should first try to understand the code you currently have and change it make it work on multiple files instead of a single one per run. There are many places around that can give you examples on how to do that, either recursively or in a loop directly into a function. There are many ways to do it and also many material around it.
That being said, you can find below one of the many approaches to solve your issue. The following code consists of two Subs that you can copy/paste into your module.
You need to change the value of HOST_PATH with the main folder and the findReplaceRange with the range to work with. You need to change "Sheet1" with the name of your worksheet and the "A1:B10" with your actual range. After that, just run the ReplaceXML2() Sub.
Note: this will update ALL XML files under the folder provided, so make sure you gave it enough testing (preferably, backup your files) before running it for the entire folder. If you have further issues I suggest asking another question.
Code:
Public Sub ReplaceXML2()
Const HOST_PATH = "C:\Users\s37739\Desktop\chap3\" ' change accordingly
Dim findReplaceRange As Range
Set findReplaceRange = ThisWorkbook.Worksheets("Sheet1").Range("A1:B10") ' change accordingly
Dim FileSystem As Object
Set FileSystem = CreateObject("Scripting.FileSystemObject")
Call RecursivelyReplaceXML(FileSystem.GetFolder(HOST_PATH), findReplaceRange)
End Sub
Public Sub RecursivelyReplaceXML(parentFolder, rFindReplaceRange As Range) ' Pass in the folder and the find-replace range
Dim subFolder As Object
For Each subFolder In parentFolder.SubFolders
RecursivelyReplaceXML subFolder, rFindReplaceRange
Next
Dim file As Object
For Each file In parentFolder.Files
If Right(file.Name, 4) = ".xml" Then
Dim iFileNum As Integer
Dim sTemp As String
Dim sBuf As String
Dim i As Long
Dim fullFileName As String
fullFileName = file.Path
iFileNum = FreeFile
Open fullFileName For Input As iFileNum
sTemp = "" ' clean up to read the next file
Do Until EOF(iFileNum)
Line Input #iFileNum, sBuf
sTemp = sTemp & sBuf & vbCrLf
Loop
Close iFileNum
' Loop over the replacements
For i = 1 To rFindReplaceRange.Rows.count
If rFindReplaceRange.Cells(i, 1) <> "" Then
sTemp = Replace(sTemp, rFindReplaceRange.Cells(i, 1), rFindReplaceRange(i, 2))
End If
Next i
' Save file
iFileNum = FreeFile
' WARNING: New name definition commented out,
' which means all files will be replaced with newer versions!!
'===
' Alter fullFileName first to save to a different file e.g.
' fullFileName = "C:\Users\s37739\Desktop\chap3\"
Open fullFileName For Output As iFileNum
Print #iFileNum, sTemp
Close iFileNum
End If
Next
End Sub

Resources