How to Store a Folder Path in Excel VBA - excel

Sub GetFolderPath()
Dim InputFolder As String
Dim OutputFolder As String
InputFolder = Application.GetOpenFilename("Folder, *")
Range("C1").Select
ActiveCell.Value = InputFolder & "\"
End Sub
I am using the code above to attempt to store, and then paste, a folder location for another macro I am running.
Any idea how to make it stop at the folder level or remove the filename from the end?
Thanks!

You could use
FileName = Dir(InputFolder)
InputFolder = Left(InputFolder, Len(InputFolder)-Len(FileName))
Dir() gets just the file name and Left() helps trim down the string to just the folder path.

There is even shorter option to get your path. Just with one single line:
'...your code
Dim InputFolder As String
InputFolder = Application.GetOpenFilename("Folder, *")
'new, single line solution
InputFolder = Mid(InputFolder, 1, InStrRev(InputFolder, Application.PathSeparator))
And I think there could be some more options available :)

If I understand right, you want to get the path to a file but you do not want to file name in the InputFolder string. If I understood correctly then this will do the trick:
Option Explicit
Sub GetFolderPath()
Dim InputFolder As String
Dim OutputFolder As String
InputFolder = Application.GetOpenFilename("Folder, *")
Range("C1").Value = getFilePath(InputFolder)
End Sub
Function getFilePath(path As String)
Dim filePath() As String
Dim finalString As String
Dim x As Integer
filePath = Split(path, "\")
For x = 0 To UBound(filePath) - 1
finalString = finalString & filePath(x) & "\"
Next
getFilePath = finalString
End Function
Also, you do not have to write the file name to the spreadsheet in order for another macro to get it. You can just call the other macro from your first macro and pass the file name as a parameter or set the file name variable as a module level variable so it can be accessed by the other macro, assuming that second macro is in the same module.

Wow, this board is incredible! I would up using casey's code and it worked perfectly :). I also added in a function to create subfolders as needed.
Here is the final product I settled on.
Option Explicit
Sub GetFolderPath()
Dim InputFolder As String
Dim OutputFolder As String
MsgBox ("Please Select the Folder of Origin")
InputFolder = Application.GetOpenFilename("Folder, *")
Range("D5").Value = getFilePath(InputFolder)
MsgBox ("Please Select the Desired Destination Root Folder")
InputFolder = Application.GetOpenFilename("Folder, *")
Range("E5").Value = getFilePath(InputFolder)
Dim OutputSubFolder As String
Dim Cell As Range
Range("E5").Select
OutputSubFolder = ActiveCell.Value
'Loop through this range which includes the needed subfolders
Range("C5:C100000").Select
For Each Cell In Selection
On Error Resume Next
MkDir OutputSubFolder & Cell
On Error GoTo 0
Next Cell
End Sub
Function getFilePath(path As String)
Dim filePath() As String
Dim finalString As String
Dim x As Integer
filePath = Split(path, "\")
For x = 0 To UBound(filePath) - 1
finalString = finalString & filePath(x) & "\"
Next
getFilePath = finalString
End Function

Related

Functions work separately but not together, returns 0 value

I recently got help here with the first function but I am stumped about why my code is not working..
I'm trying to use the ReportTimeByOP function to find the newest file located in "sFolder" that begins with "sName" and that has a "sOPID" that matches the "value38" result of the ReadTextFile function.
For whatever reason I have no trouble getting both functions to work independently but my attempts to combine them into one seamless operation have failed. What I currently have is:
Function ReadTextFile(fpath)
Dim fline As String
Dim fnumb As Long
Dim i As Long
Dim Wanted As String
fnumb = FreeFile
Open fpath For Input As #fnumb
i = 1
Do While Not EOF(fnumb)
Line Input #fnumb, fline
If i = 2 Then
Wanted = Split(fline, vbTab)(38)
Exit Do
End If
i = i + 1
Loop
Close #fnumb
MsgBox fpath
ReadTextFile = Wanted
End Function
Function ReportTimeByOP(ByVal sName As String, ByVal sFolder As String, ByVal sOPID As String)
Dim FileName As String
Dim MostRecentFile As String
Dim MostRecentDate As Date
Dim value38 As String
Dim oFSO As FileSystemObject
If Right(sFolder, 1) <> "\" Then sFolder = sFolder & "\"
Set oFSO = CreateObject("Scripting.FileSystemObject")
If oFSO.FolderExists(sFolder) Then
FileName = Dir(sFolder & sName & "*hdr.txt", 0)
If FileName <> "" Then
MostRecentFile = FileName
MostRecentDate = FileDateTime(sFolder & FileName)
Do While FileName <> ""
value38 = ReadTextFile(sFolder & FileName)
If FileDateTime(sFolder & FileName) > MostRecentDate And Trim(value38) = Trim(sOPID) Then
MostRecentFile = FileName
MostRecentDate = FileDateTime(sFolder & FileName)
value38 = ReadTextFile(sFolder & FileName)
End If
FileName = Dir
DoEvents
Loop
End If
Else
MostRecentFile = "Err: folder not found."
End If
Set oFSO = Nothing
ReportTimeByOP = MostRecentDate
End Function
Given the huge number of files, I'd skip the Dir function entirely. I'd also skip the manual sorting of the results by creation date (I'm assuming this is the criteria - if not, it should be fairly easy to modify). Let the Windows Shell do the heavy lift for you. Unlike the VBA Dir() function or the Scripting.FileSystemObject, the shell dir command has a ton of parameters that allow you to retrieve sorted output. For this purpose, going through a list of files sorted in reverse order is much, much more efficient. You can see all of the dir options here.
So, I'd approach this by shelling to a dir command that retrieves the list of files in reverse date order, pipe it to a temp file, and then pick up the temp file to go through the list. That way you can just exit when you find your first match. Then you can simplify both your loop and ReadTextFile function by using the FileSystemObject:
ReadTextFile:
Public Function ReadTextFile(target As File) As String
With target.OpenAsTextStream
If Not .AtEndOfStream Then .SkipLine
Dim values() As String
If Not .AtEndOfStream Then
values = Split(.ReadLine, vbTab)
If UBound(values) >= 38 Then
ReadTextFile = values(38)
End If
End If
.Close
End With
End Function
ReportTimeByOP:
Function ReportTimeByOP(ByVal sName As String, ByVal sFolder As String, _
ByVal sOPID As String) As Date
With New Scripting.FileSystemObject
Dim temp As String
temp = .BuildPath(.GetSpecialFolder(TemporaryFolder), .GetTempName)
Dim seeking As String
seeking = .BuildPath(sFolder, sName & "*hdr.txt")
Shell "cmd /c dir """ & seeking & """ /b /a:-d /o:-d > " & temp
'Shell is asychronous - wait .2 seconds for it to complete.
Sleep 200
With .GetFile(temp).OpenAsTextStream
Dim directory() As String
directory = Split(.ReadAll, vbNewLine)
.Close
End With
.DeleteFile temp
Dim i As Long
Dim value38 As String
Dim candidate As File
'Temp file will end with a newline, so the last element is empty.
For i = LBound(directory) To UBound(directory) - 1
Set candidate = .GetFile(.BuildPath(sFolder, directory(i)))
value38 = ReadTextFile(candidate)
If Trim$(value38) = Trim$(sOPID) Then
ReportTimeByOP = candidate.DateCreated
Exit Function
End If
Next i
End With
End Function
And this declaration somewhere:
Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Excel VBA - how to find the largest substring value in a column

I have a column in a spreadsheet.
The format of the data in each cell is aa-0001-xx.
I need to examine the whole column to find the highest value of the sequence number. this would be the substring from column4 thru column7.
I can find the sequence number using Mid(ActiveWorkbook.Sheets("Sheet1").Range("B2:B2"), 4, 4)
But I need to find the max sequence in the whole column.
I am doing this in VBA.
Any help would be appreciated.
Here is my code so far:
Private Sub CommandButton1_Click()
Dim sQuoteNumber As String
Dim sFileName As String
Dim sPathName As String
Dim checkit As String
'Log the Quote
'First, open the log file and determine the next sequential log number.
sPathName = "C:\Users\Rich\Documents\Bryan\BigProject\"
sFileName = "QuoteLog2016.xlsx"
ControlFile = ActiveWorkbook.Name
Workbooks.Open Filename:=sPathName & sFileName
'Create the new Quote Number
checkit = Mid(ActiveWorkbook.Sheets("Sheet1").Range("B2:B2"), 4, 4) ' This is a temp test line
If Mid(ActiveWorkbook.Sheets("Sheet1").Range("B2:B2"), 4, 4) = "" Then
sQuoteNumber = "16-0001"
Else
'find the biggest number
'Here I was looking to like pass the mid function to a Max function of some sort.
sQuoteNumber = "16-0002"
End If
MsgBox ("The new Quote Number is: " + sQuoteNumber)
'Save the log entry
Workbooks(sFileName).Close
All of the comments made to your answer would work well for you. It's also true that there's no evidence in your code at having attempted something, however rudimentary, and this is why answers to a rather trivial task are not forthcoming for you. Perhaps, in future, have a go at some kind of solution ( even if it feels more guesswork than anything) and people on this site will be much more supportive of you.
To set you on your way, you could make use of the Split() function which converts a String into a String array, separated by a nominated value - in the case of your quotations, you could use "-" as your separator. This might be easier than your Mid function and will deal with the case of different sized quotations.
The code below will get you started but you'd want some error handling in there to test, for example, that each cell splits appropriately or that any cells aren't blank. I'll leave all of that to you.
Option Explicit
Private mLastQuote As Long
Public Sub Test()
Initialise 'call this routine just once at the start of your project
MsgBox GetNextQuote(16) 'use the GetNextQuote() function to get next number
MsgBox GetNextQuote(16)
MsgBox GetNextQuote(16)
End Sub
Private Function GetNextQuote(prefix As Integer) As String
mLastQuote = mLastQuote + 1
GetNextQuote = CStr(prefix) & "-" & _
Format(mLastQuote, "000#")
End Function
Private Sub Initialise()
Const PATH_NAME As String = "C:\Users\Rich\Documents\Bryan\BigProject\"
Const FILE_NAME As String = "QuoteLog2016.xlsx"
Const QUOTE_COL As String = "B"
Dim wb As Workbook
Dim ws As Worksheet
Dim v As Variant
Dim r As Long
Dim parts() As String
Dim num As Long
Application.ScreenUpdating = False
Set wb = Workbooks.Open(PATH_NAME & FILE_NAME, True, True)
Set ws = wb.Worksheets("Sheet1")
'Read quote values into variant array
With ws
v = .Range(.Cells(2, QUOTE_COL), _
.Cells(.Rows.Count, QUOTE_COL).End(xlUp)) _
.Value2
End With
'Find max quote
For r = 1 To UBound(v, 1)
parts = Split(v(r, 1), "-") 'splits quote into 3 parts
num = CLng(parts(1)) 'index (1) is the middle part
If num > mLastQuote Then mLastQuote = num
Next
wb.Close False
Application.ScreenUpdating = True
End Sub

Extract a folder name from file path

I have a file path (which is a connection path for the worksheet) in the following format:
C:\ExcelFiles\Data\20140522\File1_20140522.csv
I want to extract 20140522.
I tried using responses of How to extract groups of numbers from a string in vba, but they don't seem to work in my case.
please find below
Filename = "C:\ExcelFiles\Data\20140522\File1_20140522.csv"
a = Replace(Mid(Filename, InStrRev(Filename, "_") + 1, Len(Filename)), ".csv", "")
Try the following. Folder is selected.
Sub Folder_S()
Dim sFolder As FileDialog
On Error Resume Next
Set sFolder = Application.FileDialog(msoFileDialogFolderPicker)
If sFolder.Show = -1 Then
Folder_Select sFolder.SelectedItems(1), True
End If
End Sub
Sub Folder_Select(ByVal SourceFolderName As String, ByVal IncludeSubfolders As Boolean)
Dim FSO As Object
Dim SourceFolder As Object
Dim FileItem As Object
Dim strFile As String
Dim FileName As Variant
Dim pathParts() As String
Dim pathPart As String
Dim i As Long
Set FSO = CreateObject("Scripting.FileSystemObject")
Set SourceFolder = FSO.GetFolder(SourceFolderName)
pathParts = Split(SourceFolder.Path, Application.PathSeparator)
pathPart = SourceFolder.Path
For i = 0 To UBound(pathParts)
If pathParts(i) = "20140522" Then
pathPart = pathParts(i - 0)
Exit For
End If
Next i
Row = ActiveCell.Row
With CreateObject("Scripting.Dictionary")
For Each FileItem In SourceFolder.Files
strFile = FileItem.Name
.Item(strFile) = Array(FileItem.Name)
Next FileItem
If .Count > 0 Then
For Each FileName In .Items
Cells(Row, 2).Formula = pathPart
Next FileName
End If
End With
End Sub
I found your question by searching a solution how to get a folder path from a file that is inside this folder path. But your question doesn't match exactly what I need. For those who by your question title will find it for the same purpose as I found, below is my function:
Function getFolderPathFromFilePath(filePath As String) As String
Dim lastPathSeparatorPosition As Long
lastPathSeparatorPosition = InStrRev(filePath, Application.PathSeparator)
getFolderPathFromFilePath = Left(filePath, lastPathSeparatorPosition - 1)
End Function
In some solutions for this purpose, I used FSO, but it takes resources, and I think it isn't worthy to create FSO object if you need it only for this simple function.
the accepted answer is not accurate to read the folder name. here is more dynamic code.
use splitter which splits string based on delimeter and makes an array. now read the second last element in array, thats the folder name.
Dim fileName As String
fileName = "C:\ExcelFiles\Data\20140522\File1_20140522.csv"
Dim vPathSplitter As Variant
vPathSplitter = Split(fileName, "\")
MsgBox (vPathSplitter(UBound(vPathSplitter) - 1))
The below answer gets your file path from a range, rather than a fixed string. Much more handy if your planning on getting your filename from your sheets, which I imagine you are.
Sub GetFileDate()
Dim filename As String
filename = Sheets("Sheet1").Range("C9").Value 'Or Wherever your file path is
MsgBox Replace(Right(filename, 12), ".csv", "")
End Sub
This assumes the numbers your extracting will ALWAYS be dates in YYYYMMDD format and the file type is always .csv

Getting the range used to define error bars with VBA

I have an Excel chart. One of the series has X and Y error bars, defined from worksheet ranges.
I want to get via VBA those ranges (not set them). Is this possible?
Jon Peltier has an article about error bars on his blog here
Quoting from that:
Programmatically Defining Custom Error Bars
The command to add error bars using Excel is: {Series}.ErrorBar
Direction:={xlX or xlY}, Include:=xlBoth, Type:=xlCustom, _
Amount:={positive values}, MinusValues:={negative values} Values can be a single numerical value, for example, 1, an comma-separated
array of numerical values in curly braces, such as {1,2,3,4}, or a
range address in R1C1 notation. For values in Sheet1!$G$2:$G$10, enter
the address as Sheet1!R2C7:R10C7. Combine both plus and minus in the
same command. In Excel 2007, if you don’t want to show a particular
error bar, you must enter a value of zero in this command. In 2003,
you can enter a null string “”. In Excel 2003, the range address must
begin with an equals sign, =Sheet1!R2C7:R10C7; Excel 2007 accepts the
address with or without the equals sign. Single values or arrays may
be entered with or without the equals sign in either version of Excel.
In a post on Ozgrid, Jon Peltier says
the range for custom error bar values is not exposed to VBA
If Jon says it can't be done, it can't be done.
I know I'm 8 years late to the party here... but I stumbled upon this while scouring the web for the answer to this same question. I came up empty too, so I decided to devise my own solution, and figured I might as well post it on the off chance that someone else ends up here.
It works by extracting the workbook XML to a temporary folder, locating the error bar reference in the XML, and returning it as a Range object. You therefore have to save changes to the workbook before the function will work. If you change the error bar range without saving, the function will still return the old range from the most recent save. It also will not work on files from Excel 2003 or earlier (.xls).
It's anything but elegant... but at least this is technically possible!
To use: just copy the code below into a standard module, and call GetErrorBarRange(MySeries.ErrorBars, enErrorBarPlus) for the source range of the positive error bar, or GetErrorBarRange(MySeries.ErrorBars, enErrorBarMinus) for the source range of the negative error bar (where MySeries.ErrorBars is some ErrorBars object). Passing the optional third argument AutoSave:=True will save the containing workbook automatically before looking for the error bar source ranges.
' Created by Ryan T. Miller in 2022
' You may use this code in your own work however you wish. It'd be real swell of you
' to leave this credit in if you do, but I'm not gonna force you to.
Option Explicit
Option Private Module
Public Enum EnErrorBarPlusMinus
enErrorBarPlus
enErrorBarMinus
End Enum
Private moFSO As Object
' Get error bar source range from ErrorBars object
Public Function GetErrorBarRange(oErrorBars As ErrorBars, _
PlusMinus As EnErrorBarPlusMinus, _
Optional AutoSave As Boolean) As Range
Dim oFile As Object
Dim strTempDir As String
Dim strSubfolder As String
Dim oSeries As Series
Dim oChart As Chart
Dim oSheet As Object
Dim oWb As Workbook
Dim strPrefix As String
Dim strSeriesName As String
Dim strChartName As String
Dim strSheetName As String
Dim strXMLFile As String
Dim strXPath As String
Dim strCurrentSheet As String
Dim strRelId As String
Dim strDrawingXml As String
Dim strChartXml As String
Dim strErrValType As String
Dim strErrBarType As String
Dim strErrBarFormula As String
Dim rngResult As Range
On Error GoTo CleanUp
If Not (PlusMinus = enErrorBarMinus _
Or PlusMinus = enErrorBarPlus) Then Exit Function
Set moFSO = CreateObject("Scripting.FileSystemObject")
Application.Cursor = xlWait
' Set Series, Chart, Sheet, and Workbook objects
Set oSeries = oErrorBars.Parent
Set oChart = oSeries.Parent.Parent
If TypeOf oChart.Parent Is ChartObject Then
' Chart is on a worksheet
Set oSheet = oChart.Parent.Parent
strPrefix = "work"
Else
' Chart is on its own chart sheet
Set oSheet = oChart
strPrefix = "chart"
End If
Set oWb = oSheet.Parent
If AutoSave Then oWb.Save
' Name of the series, chart & its parent sheet
strSeriesName = oSeries.Name
strChartName = oChart.Parent.Name
strSheetName = oSheet.CodeName
strTempDir = ExtractWorkbookXMLToTemp(oWb)
' Loop over worksheet/chartsheet XML files & find the one where /worksheet/sheetPr/#codeName=strSheetName
' Then get strRelId from /worksheet/drawing/#r:id
' This is the ID which specifies which relationship links the sheet to the drawings.
strSubfolder = moFSO.BuildPath(strTempDir, "xl\" & strPrefix & "sheets")
strXPath = "/x:" & strPrefix & "sheet/x:sheetPr/#codeName"
For Each oFile In moFSO.GetFolder(strSubfolder).Files
strXMLFile = moFSO.BuildPath(strSubfolder, oFile.Name)
strCurrentSheet = GetXPathFromXMLFile(strXMLFile, strXPath)
If strSheetName = strCurrentSheet Then Exit For
Next oFile
strXPath = "/x:" & strPrefix & "sheet/x:drawing/#r:id"
strRelId = GetXPathFromXMLFile(strXMLFile, strXPath)
' Open the _rels XML associated with the correct sheet.
' Then get strDrawingXml from /Relationships/Relationship[#Id='strRelId']/#Target
' This is the name of the drawing XML.
strSubfolder = strSubfolder & "\_rels"
strXMLFile = moFSO.BuildPath(strSubfolder, moFSO.GetFileName(strXMLFile)) & ".rels"
strXPath = "/rel:Relationships/rel:Relationship[#Id='" & strRelId & "']/#Target"
strDrawingXml = GetXPathFromXMLFile(strXMLFile, strXPath)
strDrawingXml = Replace$(Replace$(strDrawingXml, "../", "/"), "/", "\")
' Open the correct drawing XML file (strDrawingXml)
' Then get strRelId from xdr:wsDr//xdr:graphicFrame[xdr:nvGraphicFramePr/xdr:cNvPr/#name='strChartName']/a:graphic/a:graphicData/c:chart/#r:id
' Or, if oSheet is a ChartSheet, there will only be 1 chart, so just get xdr:wsDr//xdr:graphicFrame/a:graphicData/a:graphic/c:chart/#r:id
' This is the ID which specifies which relationship links the drawing to the chart.
strXMLFile = moFSO.BuildPath(strTempDir, "xl" & strDrawingXml)
strXPath = "xdr:wsDr//xdr:graphicFrame" & _
IIf(TypeOf oChart.Parent Is ChartObject, "[xdr:nvGraphicFramePr/xdr:cNvPr/#name='" & strChartName & "']", vbNullString) & _
"/a:graphic/a:graphicData/c:chart/#r:id"
strRelId = GetXPathFromXMLFile(strXMLFile, strXPath)
' Open the _rels associated with the correct drawing XML.
' Then get strChartXml = /Relationships/Relationship[#Id='strRelId']/#Target
' This is the name of the chart XML.
strSubfolder = moFSO.GetParentFolderName(strXMLFile) & "\_rels"
strXMLFile = moFSO.BuildPath(strSubfolder, moFSO.GetFileName(strXMLFile)) & ".rels"
strXPath = "/rel:Relationships/rel:Relationship[#Id='" & strRelId & "']/#Target"
strChartXml = GetXPathFromXMLFile(strXMLFile, strXPath)
strChartXml = Replace$(Replace$(strChartXml, "../", "/"), "/", "\")
' Open the correct chart XML file (strChartXml)
strXMLFile = moFSO.BuildPath(strTempDir, "xl" & strChartXml)
' Get error bar value type. If the error bar is set to a Range then this must be 'cust'.
strXPath = "/c:chartSpace/c:chart//c:ser[c:tx//c:v[text()='" & strSeriesName & "']]/c:errBars/c:errValType/#val"
strErrValType = GetXPathFromXMLFile(strXMLFile, strXPath)
' Get error bar type. This can be "minus", "plus", or "both" depending on which error bar(s) exist(s).
strXPath = "/c:chartSpace/c:chart//c:ser[c:tx//c:v[text()='" & strSeriesName & "']]/c:errBars/c:errBarType/#val"
strErrBarType = GetXPathFromXMLFile(strXMLFile, strXPath)
' Get the Range address for either the "minus" or "plus" error bar and set it to the final result.
If strErrValType = "cust" Then
strXPath = "/c:chartSpace/c:chart//c:ser[c:tx//c:v[text()='" & strSeriesName & "']]/c:errBars"
If PlusMinus = enErrorBarMinus And (strErrBarType = "both" Or strErrBarType = "minus") Then
strXPath = strXPath & "/c:minus/c:numRef/c:f"
ElseIf PlusMinus = enErrorBarPlus And (strErrBarType = "both" Or strErrBarType = "plus") Then
strXPath = strXPath & "/c:plus/c:numRef/c:f"
EndIf
strErrBarFormula = GetXPathFromXMLFile(strXMLFile, strXPath)
strErrBarFormula = "'[" & oWb.Name & "]" & Replace$(strErrBarFormula, "!", "'!")
Set rngResult = Application.Range(strErrBarFormula)
End If
Set GetErrorBarRange = rngResult
CleanUp:
' Delete the temporary extracted XML data
With moFSO
If .FolderExists(strTempDir) Then .DeleteFolder strTempDir
End With
Set moFSO = Nothing
' Free the cursor
Application.Cursor = xlDefault
End Function
' Get the value of an XML node by an XPath search string
Private Function GetXPathFromXMLFile(ByVal strXMLFile As String, ByVal strXPath As String) As String
Dim objXMLDoc As Object
Dim strNS As String
Dim objXMLNode As Object
' Load the XML file
Set objXMLDoc = CreateObject("MSXML2.DOMDocument.6.0")
objXMLDoc.Load strXMLFile
' These are all the XML namespaces related to the current task
strNS = Join$(Array( _
"xmlns:x=""http://schemas.openxmlformats.org/spreadsheetml/2006/main""", _
"xmlns:r=""http://schemas.openxmlformats.org/officeDocument/2006/relationships""", _
"xmlns:mc=""http://schemas.openxmlformats.org/markup-compatibility/2006""", _
"xmlns:x14ac=""http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac""", _
"xmlns:xr=""http://schemas.microsoft.com/office/spreadsheetml/2014/revision""", _
"xmlns:xr2=""http://schemas.microsoft.com/office/spreadsheetml/2015/revision2""", _
"xmlns:xr3=""http://schemas.microsoft.com/office/spreadsheetml/2016/revision3""", _
"xmlns:rel=""http://schemas.openxmlformats.org/package/2006/relationships""", _
"xmlns:xdr=""http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing""", _
"xmlns:a=""http://schemas.openxmlformats.org/drawingml/2006/main""", _
"xmlns:c=""http://schemas.openxmlformats.org/drawingml/2006/chart""", _
"xmlns:c16r2=""http://schemas.microsoft.com/office/drawing/2015/06/chart""" _
))
objXMLDoc.SetProperty "SelectionLanguage", "XPath"
objXMLDoc.SetProperty "SelectionNamespaces", strNS
objXMLDoc.resolveExternals = True
' Select the XML node and return its text value
Set objXMLNode = objXMLDoc.SelectSingleNode(strXPath)
If Not objXMLNode Is Nothing Then
GetXPathFromXMLFile = objXMLNode.Text
End If
End Function
' If workbook path is a OneDrive URL or a network share URL then resolve it to a local path with a drive letter
Private Function LocalFilePath(ByVal strFilePath As String)
strFilePath = OneDriveLocalFilePath(strFilePath)
strFilePath = NetworkLocalFilePath(strFilePath)
LocalFilePath = strFilePath
End Function
' If workbook path is a OneDrive URL then resolve it to a local path with a drive letter
Private Function OneDriveLocalFilePath(ByVal strFilePath As String) As String
Dim strOneDrivePath As String
Dim strLocalPath As String
If strFilePath Like "*my.sharepoint.com*" Then
strOneDrivePath = Environ$("OneDriveCommercial")
If strOneDrivePath = vbNullString Then strOneDrivePath = Environ$("OneDrive")
strLocalPath = strOneDrivePath & "/" & Split(strFilePath, "/", 7)(6)
OneDriveLocalFilePath = Replace$(strLocalPath, "/", "\")
ElseIf strFilePath Like "*d.docs.live.net*" Then
strOneDrivePath = Environ$("OneDriveConsumer")
If strOneDrivePath = vbNullString Then strOneDrivePath = Environ$("OneDrive")
strLocalPath = strOneDrivePath & "/" & Split(strFilePath, "/", 5)(4)
OneDriveLocalFilePath = Replace$(strLocalPath, "/", "\")
Else
OneDriveLocalFilePath = strFilePath
End If
End Function
' If workbook path is a network share URL then resolve it to a local path with a drive letter
Private Function NetworkLocalFilePath(ByVal strFilename As String) As String
On Error Resume Next
Dim ShellScript As Object
Dim i As Long
Dim strDriveLetter As String * 1
Dim strRemotePath As String
Set ShellScript = CreateObject("WScript.Shell")
For i = 97 To 122 ' a to z
strDriveLetter = Chr$(i)
strRemotePath = ShellScript.RegRead("HKEY_CURRENT_USER\Network\" & strDriveLetter & "\RemotePath")
If Err.Number = 0 Then
If strFilename Like strRemotePath & "*" Then
NetworkLocalFilePath = Replace$(strFilename, strRemotePath, UCase$(strDriveLetter) & ":", Count:=1)
Exit Function
End If
Else
Err.Clear
End If
Next i
NetworkLocalFilePath = strFilename
End Function
' Extract workbook XML to temporary directory
Private Function ExtractWorkbookXMLToTemp(oWb As Workbook) As String
Dim strTempDir As String
Dim strExt As String
Dim strTempWb As String
Dim strWbLocal As String
Dim strZipFile As String
On Error GoTo CleanUp
' Create a temporary copy of the workbook
With moFSO
strTempDir = .BuildPath(Environ$("TEMP"), _
Replace$(.GetTempName, ".tmp", vbNullString))
strExt = .GetExtensionName(oWb.Name)
strTempWb = strTempDir & "." & strExt
strWbLocal = LocalFilePath(oWb.FullName)
.CopyFile strWbLocal, strTempWb
End With
' Rename the temporary copy from .xls_ to .zip
strZipFile = strTempDir & ".zip"
Name strTempWb As strZipFile
' Unzip the .zip file to a temporary folder
MkDir strTempDir
UnzipFiles strZipFile, strTempDir
' Return the name of the temporary directory
ExtractWorkbookXMLToTemp = strTempDir
CleanUp:
' Delete the temporary ZIP file
With moFSO
If .FileExists(strZipFile) Then .DeleteFile strZipFile
End With
End Function
' Unzip all the files in 'varZipFile' into the folder 'varDestDir'
Private Sub UnzipFiles(ByVal varZipFile As Variant, ByVal varDestDir As Variant)
Dim oShellApp As Object
Const NO_PROGRESS_DIALOG As Integer = &H4
Set oShellApp = CreateObject("Shell.Application")
If Not varDestDir Like "*\" Then varDestDir = varDestDir & "\"
With oShellApp
.Namespace(varDestDir).CopyHere .Namespace(varZipFile).Items, NO_PROGRESS_DIALOG
End With
On Error Resume Next
With oShellApp
Do Until .Namespace(varZipFile).Items.Count = .Namespace(varDestDir).Items.Count
Application.Wait Date + (VBA.Timer + 1!) / 86400
Loop
End With
On Error GoTo 0
End Sub

trying to store text file rows in VBA

Greetings, I'm hoping for help in figuring out how to store each row of a text file read into a VBA program as a string. I want to modify one of the strings and then put them all back together, but do not know how to read through a text file and store each row as a separate variable in an intelligent way. Thanks for any help you can provide!
If you don't want to add references, you could just go with straight vba code.
Take for instance the following file wordlist.txt:
realize
empty
theorize
line
socialize
here
analyze
The following code uses two methods to do as you described (one more common than the other):
Option Explicit
Sub main()
Dim sFileName As String
Dim sMergedLineArray() As String
Dim sTextToFind As String
Dim sReplacementText As String
Dim sOutputFile As String
Const MY_DELIMITER = "|"
sFileName = "C:\deleteme\wordlist.txt"
sMergedLineArray = ReadFileIntoArray(sFileName)
sTextToFind = "ze"
sReplacementText = "se"
'Loop through each value in the array and make a change if you need to
Dim x As Integer
For x = 0 To UBound(sMergedLineArray)
If InStr(1, sMergedLineArray(x), sTextToFind, vbTextCompare) > 0 Then
sMergedLineArray(x) = Replace(sMergedLineArray(x), sTextToFind, sReplacementText, 1, -1, vbTextCompare)
End If
Next x
sOutputFile = "C:\deleteme\UK_Version.txt"
If Not SpitFileOut(sOutputFile, sMergedLineArray) Then
MsgBox "It didn't work :("
End If
'OR...put it all together, make a mass change and split it back out (this seems unlikely, but throwing it in there anyway)
sTextToFind = "se"
sReplacementText = "ze"
Dim sBigString As String
Dim sNewArray As Variant
sBigString = Join(sMergedLineArray, MY_DELIMITER)
sBigString = Replace(sBigString, sTextToFind, sReplacementText, 1, -1, vbTextCompare)
sNewArray = Split(sBigString, MY_DELIMITER, -1, vbTextCompare)
sOutputFile = "C:\deleteme\American_Version.txt"
If Not SpitFileOut(sOutputFile, sNewArray) Then
MsgBox "It didn't work"
End If
MsgBox "Finished!"
End Sub
Function ReadFileIntoArray(sFileName As String) As String()
Dim sText As String
Dim sLocalArray() As String
Dim iFileNum As Integer
Dim iLineCount As Integer
iFileNum = FreeFile
Open sFileName For Input As #iFileNum
Do Until EOF(iFileNum)
Input #iFileNum, sText
ReDim Preserve sLocalArray(iLineCount)
sLocalArray(iLineCount) = sText
iLineCount = iLineCount + 1
Loop
Close #iFileNum
ReadFileIntoArray = sLocalArray
End Function
Function SpitFileOut(sFileName As String, sMyArray As Variant) As Boolean
Dim iFileNum As Integer
Dim iCounter As Integer
SpitFileOut = False
iFileNum = FreeFile
Open sFileName For Output As #iFileNum
For iCounter = 0 To UBound(sMyArray)
Print #iFileNum, sMyArray(iCounter)
Next
Close #iFileNum
SpitFileOut = True
End Function
If you run the main sub, you'll end up with two files:
UK_Version.txt: This is the result of the first method
American_Version.txt: This is the result of the second
There's lesson 1 of VBA, young Padawan; absorb it, learn and change your login name :P
Look into the FileSystemObject (ref: 1, 2, 3)
You have to go to <Tools/References> menu and include the Microsoft Scripting Runtime and create a global variable Global fso as New FileSystemObject. Now anywhere in your code do things like fso.OpenTextFile() which returns a TextStream. Each TextStream has methods loke ReadLine(), ReadAll(), SkipLine(), WriteLine(), etc ...
Here is a quick sample code.
Global fso as New FileSystemObject
Sub TEST()
Dim ts As TextStream
Set ts = fso.OpenTextFile("text_file.txt", ForReading, False)
Dim s As String
s = ts.ReadAll()
End Sub

Resources