I'm trying to send a local photo using VBA or VBScript. The solutions I found are either for sending URLs instead of files, or for other than VBA or VBScript.
Sub TelegramAuto()
Dim ws As Worksheet
Set ws = Sheets("hidden")
Set ws1 = Sheets("Dashboard")
Dim objRequest As Object
Dim strChatId As String
Dim strMessage As String
Dim strPhoto As String
Dim strPostPhoto As String
Dim strPostData As String
Dim strResponse As String
strChatId = <id>
strMessage = ws.Range("J5") & Format(ws1.Range("D2"), "mm/dd/yyyy") & " " & ws1.Range("D4") & " " & ws1.Range("D6") _
& " " & ws1.Range("K6")
strPhoto = "C:/Users/mhjong/Desktop/GP_FS_Breakdown.png"
strPostData = "chat_id=" & strChatId & "&text=" & strMessage
strPostPhoto = "chat_id=" & strChatId & "&photo=" & strPhoto
Set objRequest = CreateObject("MSXML2.XMLHTTP")
With objRequest
.Open "POST", "https://api.telegram.org/bot<token>/sendMessage?", False
.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
.send (strPostData)
End With
With objRequest
.Open "POST", "https://api.telegram.org/bot<token>/sendPhoto?", False
.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
.Send (strPostPhoto)
End With
End Sub
I can send messages. I cannot find the syntax to upload a local image and send it to Telegram.
strPhoto = "image link"
strPostPhoto = "chat_id=" & strChatId & "&photo=" & strPhoto
With objRequest
.Open "POST", "https://api.telegram.org/bot<Token>/sendPhoto?" & strPostPhoto, False
.send
End With
Public Function tmBotSend(Token As String, chat_id As String, Optional text As String = "", Optional filename As String = "", Optional pavd As String = "") As String
'https://www.planetaexcel.ru/forum/index.php?PAGE_NAME=message&FID=1&TID=93149&TITLE_SEO=93149-kak-sdelat-otpravku-v-telegram-iz-makrosa-vba-excel&MID=1193376#message1193376
'pavd as photo animation audio voice video document
'4096 chars for message.text, 200 chars for message.caption
Const adTypeBinary = 1
Const adTypeText = 2
Const adModeReadWrite = 3
Const telegram = "https://api.telegram.org/bot"
Dim part As String
part = bond("--") & form("chat_id") & chat_id & bond()
Dim dfn As String
If Len(filename) Then dfn = Dir(filename)
Dim caption As String
Dim send As String
If Len(dfn) Then
caption = "caption"
Select Case LCase(pavd)
Case "photo", "animation", "audio", "voice", "video", "document"
send = LCase(pavd)
Case Else
dfnA = Split(LCase(dfn), ".")
Select Case dfnA(UBound(dfnA))
Case "jpg", "jpeg", "png"
send = "photo"
Case "gif", "apng"
send = "animation"
Case "mp4"
send = "video"
Case "mp3", "m4a"
send = "audio"
Case "ogg"
send = "voice"
Case Else
send = "document"
End Select
End Select
Else
caption = "text"
send = "message"
End If
part = part & form(caption) & text
Dim file
Dim body
With CreateObject("ADODB.Stream")
If Len(dfn) Then
' filename
part = part & bond() & form(send, dfn)
' read file as binary
.Mode = adModeReadWrite
.Type = adTypeBinary
.Open
.LoadFromFile filename
.Position = 0
file = .Read
.Close
End If
' combine part, file , end
.Type = adTypeBinary
.Open
.Position = 0
.Write ToBytes(part)
'Debug.Print part
If Len(dfn) Then .Write file
.Write ToBytes(bond(suff:="--"))
.Position = 0
body = .Read
.Close
End With
With CreateObject("MSXML2.XMLHTTP")
'Debug.Print telegram & Token & "/send" & StrConv(send, vbProperCase)
.Open "POST", telegram & Token & "/send" & StrConv(send, vbProperCase), False
.setRequestHeader "Content-Type", "multipart/form-data; boundary=" & bond("", "")
.send body
tmBotSend = .responseText
'Debug.Print .responseText
End With
End Function
Function ToBytes(str As String) As Variant
Const adTypeBinary = 1
Const adTypeText = 2
Const adModeReadWrite = 3
With CreateObject("ADODB.Stream")
.Mode = adModeReadWrite
.Type = adTypeText
.Charset = "UTF-8" '"_autodetect"
.Open
.WriteText str
.Position = 0
.Type = adTypeBinary
ToBytes = .Read
.Close
End With
End Function
Private Function bond(Optional pref As String = vbCrLf & "--", Optional suff As String = vbCrLf, Optional BOUNDARY As String = "--OYWFRYGNCYQAOCCT44655,4239930556") As String
bond = pref & BOUNDARY & suff
End Function
Private Function form(ByVal name As String, Optional ByVal filename As String = "") As String
form = "Content-Disposition: form-data; name=""" & name & """"
If Len(filename) Then form = form & "; filename=""" & filename & """"
form = form & vbCrLf & vbCrLf
End Function
I'm currently using the below code in a VB.Net console app that takes the contents of a text file and extracts certain info and then exports it to a CSV.
All seems to work well but the problem is the file originally comes through as a PDF (only option possible) and i have to manually open the file in Adobe and 'Save as Text'.
Is there a way of either automating the conversion of PDF to text file or reading the PDF in place of the text file.
Any guidance or options would be appreciated
Dim iLine, iEnd, c, iField As Integer
Dim iSecs, iMax As Long
Dim sText, sTemp, sSchema As String
Dim sHotel, sEndDate, sMon, sPLU, sTots, sValue, sDept, sFile, sOutFile, sDesc As String
Dim tdate As Date
Dim con As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0; Data Source=C:\temp\TX.accdb;")
Dim LUse As Boolean
sHotel = "Unknown Hotel"
sEndDate = "01/01/2015"
sMon = "MAR"
sPLU = ""
sTots = "0"
sValue = "0"
sDept = "Unknown Dept"
sDesc = ""
LUse = True
sTemp = ""
iField = 0
sSchema = "Chester"
'Open input file
sFile = "c:\temp\input.txt"
Dim InFile As New System.IO.StreamReader(sFile)
'Open lookup data table
con.Open()
Dim dbAdapter As OleDbDataAdapter = New OleDbDataAdapter( _
"SELECT * FROM Plookup", con)
Dim dsTX As DataSet = New DataSet()
Dim changes As DataTable
Dim cmdbuilder As OleDbCommandBuilder = New OleDbCommandBuilder(dbAdapter)
dbAdapter.FillSchema(dsTX, SchemaType.Source, "Plookup")
dbAdapter.Fill(dsTX, "Plookup")
Dim rstx As DataTable = dsTX.Tables(0)
iMax = rstx.Rows.Count
Dim productrow() As Data.DataRow
'Open Output file
iSecs = Timer
sOutFile = "c:\temp\TX" & Format$(Now, "yymmdd") & Trim$(Str$(iSecs)) & ".csv"
FileCopy(sFile, "c:\temp\TX" & Format$(Now, "yymmdd") & Trim$(Str$(iSecs)) & ".txt")
Dim OutFile As New System.IO.StreamWriter(sOutFile)
'Write header
OutFile.WriteLine("outlet,dept,epos,tots sold,total price,date of sales")
iLine = 0
Do While InFile.Peek() <> -1
'Read in text
iLine = iLine + 1
sText = InFile.ReadLine
sText = sText.Replace(",", "")
If Len(sText) > 2 And Len(sText) < 9 Then
If Mid$(sText, 3, 1) = "-" Then ' Department Name
sText = sText & Space(9 - Len(sText))
End If
End If
'Process all rows except header row - read data into array
If Len(sText) > 8 Then
Select Case Left(sText, 7)
Case "Consoli" ' Ignore
Case "Quanti " ' Ignore
Case "Group b" ' Ignore - but next row is the Hotel Name
iLine = iLine + 1
sText = InFile.ReadLine
sText = sText.Replace(",", "")
sHotel = Trim$(Left(sText, 20)) 'The username follows so we may truncate the hotel name
Case "Date ra" ' End date
sEndDate = Mid$(sText, 29, 2) & "/" & Mid$(sText, 32, 2) & "/" & Mid$(sText, 35, 4)
tdate = CDate(sEndDate).AddDays(-1)
sEndDate = tdate.ToString("dd/MM/yyyy")
Case Else 'Possible Code
If Mid$(sText, 3, 1) = "-" Then ' Department Name
sDept = Trim(sText)
Else
If IsNumeric(Left(sText, 7)) Then 'Got a code
sPLU = Trim(Str(Val(Left(sText, 7))))
'We don't know where the description ends as it contains spaces
'So best way is to start at the end and work back...
iEnd = Len(sText)
iField = 0
For c = iEnd To 9 Step -1
If Not (Mid(sText, c, 1) = " ") Or iField > 10 Then
sTemp = Mid(sText, c, 1) & sTemp
Else
iField = iField + 1
If iField = 9 Then
sValue = sTemp
ElseIf iField = 11 Then
sTots = sTemp
End If
sTemp = ""
End If
Next
If iField = 10 Then
sTots = Trim(sTemp)
sDesc = ""
Else
sDesc = Trim$(sTemp)
End If
'lookup code
productrow = rstx.Select("FileID = 'Chester' and PLU = '" & sPLU & "'")
If productrow.Length = 0 Then ' product not found
iMax = iMax + 1
rstx.Rows.Add(sSchema, sPLU, sDesc, False)
LUse = True
Else
LUse = Not productrow(0)("Exclude")
End If
If (Val(sTots) + Val(sValue) > 0) And LUse Then ' We have a non-zero sale or value and it is not excluded
OutFile.WriteLine(sHotel & "," & sDept & "," & sPLU & "," & sTots & "," & sValue & "," & sEndDate)
End If
End If
End If
End Select
End If
Loop
'dbAdapter.Update(dsTX.Tables(0))
'Close input / output csv files
'rstx.Rows.Add("303030", "Another Test", False)
dbAdapter.UpdateCommand = cmdbuilder.GetUpdateCommand(True)
dbAdapter.InsertCommand = cmdbuilder.GetInsertCommand(True)
dbAdapter.DeleteCommand = cmdbuilder.GetDeleteCommand()
changes = rstx.GetChanges()
If changes IsNot Nothing Then dbAdapter.Update(changes)
InFile.Close()
OutFile.Close()
con.Close()
Try itextSharp. itextSharp is a .NET DLL with the help of which you can extract content from PDF. Click here for reference & sample code(although code is in c#, its just a reference to give you an idea).
I am looking for a way to convert a textfile with UTF8 encoding to ANSI encoding.
How can i go around and achieve this in Visual Basic (VB6) and or vbscript?
If your files aren't truly enormous (e.g. even merely 40MB can be painfully slow) you can do this using the following code in VB6, VBA, or VBScript:
Option Explicit
Private Const adReadAll = -1
Private Const adSaveCreateOverWrite = 2
Private Const adTypeBinary = 1
Private Const adTypeText = 2
Private Const adWriteChar = 0
Private Sub UTF8toANSI(ByVal UTF8FName, ByVal ANSIFName)
Dim strText
With CreateObject("ADODB.Stream")
.Open
.Type = adTypeBinary
.LoadFromFile UTF8FName
.Type = adTypeText
.Charset = "utf-8"
strText = .ReadText(adReadAll)
.Position = 0
.SetEOS
.Charset = "_autodetect" 'Use current ANSI codepage.
.WriteText strText, adWriteChar
.SaveToFile ANSIFName, adSaveCreateOverWrite
.Close
End With
End Sub
UTF8toANSI "UTF8-wBOM.txt", "ANSI1.txt"
UTF8toANSI "UTF8-noBOM.txt", "ANSI2.txt"
MsgBox "Complete!", vbOKOnly, WScript.ScriptName
Note that it will handle UTF-8 input files either with or without a BOM.
Using strong typing and early binding will improve performance a hair in VB6, and you won't need to declare those Const values. This isn't an option in script though.
For VB6 programs that need to process very large files you might be better off using VB6 native I/O against Byte arrays and use an API call to convert the data in chunks. This adds the extra messiness of finding the character boundaries though (UTF-8 uses a variable number of bytes per character). You'd need to scan each data block you read to find a safe ending point for an API translation.
I'd look at MultiByteToWideChar() and WideCharToMultiByte() to get started.
Note that UTF-8 often "arrives" with LF line delimiters instead of CRLF.
I'm using these helper functions
Private Function pvReadFile(sFile)
Const ForReading = 1
Dim sPrefix
With CreateObject("Scripting.FileSystemObject")
sPrefix = .OpenTextFile(sFile, ForReading, False, False).Read(3)
End With
If Left(sPrefix, 3) <> Chr(&HEF) & Chr(&HBB) & Chr(&HBF) Then
With CreateObject("Scripting.FileSystemObject")
pvReadFile = .OpenTextFile(sFile, ForReading, False, Left(sPrefix, 2) = Chr(&HFF) & Chr(&HFE)).ReadAll()
End With
Else
With CreateObject("ADODB.Stream")
.Open
If Left(sPrefix, 2) = Chr(&HFF) & Chr(&HFE) Then
.Charset = "Unicode"
ElseIf Left(sPrefix, 3) = Chr(&HEF) & Chr(&HBB) & Chr(&HBF) Then
.Charset = "UTF-8"
Else
.Charset = "_autodetect"
End If
.LoadFromFile sFile
pvReadFile = .ReadText
End With
End If
End Function
Private Function pvWriteFile(sFile, sText, lType)
Const adSaveCreateOverWrite = 2
With CreateObject("ADODB.Stream")
.Open
If lType = 2 Then
.Charset = "Unicode"
ElseIf lType = 3 Then
.Charset = "UTF-8"
Else
.Charset = "_autodetect"
End If
.WriteText sText
.SaveToFile sFile, adSaveCreateOverWrite
End With
End Function
I found out that "native" FileSystemObject reading of ANSI and UTF-16/UCS-2 files is much faster that ADODB.Stream hack.
I'm using this script to convert any character set or code page (that i'm aware of).
This script can also handle large files (over one gigabytes), because it streams one line at a time.
' - ConvertCharset.vbs -
'
' Inspired by:
' http://www.vbforums.com/showthread.php?533879-Generate-text-files-in-IBM-850-encoding
' http://stackoverflow.com/questions/5182102/vb6-vbscript-change-file-encoding-to-ansii/5186170#5186170
' http://stackoverflow.com/questions/13130214/how-to-convert-a-batch-file-stored-in-utf-8-to-something-that-works-via-another
'
' Start Main
Dim objArguments
Dim strSyntaxtext, strInputCharset, strOutputCharset, strInputFile, strOutputFile
Dim intReadPosition, intWritePosition
Dim arrCharsets
Const adReadAll = -1
Const adReadLine = -2
Const adSaveCreateOverWrite = 2
Const adSaveCreateNotExist = 1
Const adTypeBinary = 1
Const adTypeText = 2
Const adWriteChar = 0
Const adWriteLine = 1
strSyntaxtext = strSyntaxtext & "Converts the charset of the input text file to output file." & vbCrLf
strSyntaxtext = strSyntaxtext & "Syntax: " & vbCrLf
strSyntaxtext = strSyntaxtext & WScript.ScriptName & " /InputCharset:utf-8|windows-1252|ibm850|..." & vbCrLf
strSyntaxtext = strSyntaxtext & " /OutputCharset:utf-8|windows-1252|ibm850|..." & vbCrLf
strSyntaxtext = strSyntaxtext & " /InputFile:\\path\to\inputfile.ext" & vbCrLf
strSyntaxtext = strSyntaxtext & " /OutputFile:\\path\to\outputfile.ext" & vbCrLf
strSyntaxtext = strSyntaxtext & " [/ShowAllCharSets]" & vbCrLf & vbCrLf
strSyntaxtext = strSyntaxtext & "Example:" & vbCrLf
strSyntaxtext = strSyntaxtext & WScript.ScriptName & " /InputCharset:ibm850 /OutputCharset:utf-8 /InputFile:my_dos.txt /OutputFile:my_utf-8.txt" & vbCrLf
Set objArgumentsNamed = WScript.Arguments.Named
If objArgumentsNamed.Count = 0 Then
WScript.Echo strSyntaxtext
WScript.Quit(99)
End If
arrCharsets = Split("big5,big5-hkscs,euc-jp,euc-kr,gb18030,gb2312,gbk,ibm-thai," &_
"ibm00858,ibm01140,ibm01141,ibm01142,ibm01143,ibm01144," &_
"ibm01145,ibm01146,ibm01147,ibm01148,ibm01149,ibm037," &_
"ibm1026,ibm273,ibm277,ibm278,ibm280,ibm284,ibm285,ibm297," &_
"ibm420,ibm424,ibm437,ibm500,ibm775,ibm850,ibm852,ibm855," &_
"ibm857,ibm860,ibm861,ibm862,ibm863,ibm864,ibm865,ibm866," &_
"ibm869,ibm870,ibm871,iso-2022-jp,iso-2022-kr,iso-8859-1," &_
"iso-8859-13,iso-8859-15,iso-8859-2,iso-8859-3,iso-8859-4," &_
"iso-8859-5,iso-8859-6,iso-8859-7,iso-8859-8,iso-8859-9," &_
"koi8-r,koi8-u,shift_jis,tis-620,us-ascii,utf-16,utf-16be," &_
"utf-16le,utf-7,utf-8,windows-1250,windows-1251,windows-1252," &_
"windows-1253,windows-1254,windows-1255,windows-1256," &_
"windows-1257,windows-1258,unicode", ",")
Set objFileSystem = CreateObject("Scripting.FileSystemObject")
For Each objArgumentNamed in objArgumentsNamed
Select Case Lcase(objArgumentNamed)
Case "inputcharset"
strInputCharset = LCase(objArgumentsNamed(objArgumentNamed))
If Not IsCharset(strInputCharset) Then
WScript.Echo "The InputCharset (" & strInputCharset & ") is not valid, quitting. The valid charsets are:" & vbCrLf
x = ShowCharsets()
WScript.Quit(1)
End If
Case "outputcharset"
strOutputCharset = LCase(objArgumentsNamed(objArgumentNamed))
If Not IsCharset(strOutputCharset) Then
WScript.Echo "The strOutputCharset (" & strOutputCharset & ") is not valid, quitting. The valid charsets are:" & vbCrLf
x = ShowCharsets()
WScript.Quit(2)
End If
Case "inputfile"
strInputFile = LCase(objArgumentsNamed(objArgumentNamed))
If Not objFileSystem.FileExists(strInputFile) Then
WScript.Echo "The InputFile (" & strInputFile & ") does not exist, quitting." & vbCrLf
WScript.Quit(3)
End If
Case "outputfile"
strOutputFile = LCase(objArgumentsNamed(objArgumentNamed))
If objFileSystem.FileExists(strOutputFile) Then
WScript.Echo "The OutputFile (" & strOutputFile & ") exists, quitting." & vbCrLf
WScript.Quit(4)
End If
Case "showallcharsets"
x = ShowCharsets()
Case Else
WScript.Echo "Unknown parameter, quitting: /" & objArgumentNamed & ":" & objArgumentsNamed(objArgumentNamed)
WScript.Echo strSyntaxtext
End Select
Next
If Len(strInputCharset) > 0 And Len(strOutputCharset) > 0 And Len(strInputFile) > 0 And Len(strOutputFile) Then
Set objInputStream = CreateObject("ADODB.Stream")
Set objOutputStream = CreateObject("ADODB.Stream")
With objInputStream
.Open
.Type = adTypeBinary
.LoadFromFile strInputFile
.Type = adTypeText
.Charset = strInputCharset
intWritePosition = 0
objOutputStream.Open
objOutputStream.Charset = strOutputCharset
Do While .EOS <> True
strText = .ReadText(adReadLine)
objOutputStream.WriteText strText, adWriteLine
Loop
.Close
End With
objOutputStream.SaveToFile strOutputFile , adSaveCreateNotExist
objOutputStream.Close
WScript.Echo "The " & objFileSystem.GetFileName(strInputFile) & " was converted to " & objFileSystem.GetFileName(strOutputFile) & " OK."
End If
' End Main
' Start Functions
Function IsCharset(strMyCharset)
IsCharset = False
For Each strCharset in arrCharsets
If strCharset = strMyCharset Then
IsCharset = True
Exit For
End If
Next
End Function
Function ShowCharsets()
strDisplayCharsets = ""
intCounter = 0
For Each strcharset in arrCharsets
intCounter = intCounter + Len(strcharset) + 1
strDisplayCharsets = strDisplayCharsets & strcharset & ","
If intCounter > 67 Then
intCounter = 0
strDisplayCharsets = strDisplayCharsets & vbCrLf
End If
Next
strDisplayCharsets = Mid(strDisplayCharsets, 1, Len(strDisplayCharsets)-1)
WScript.Echo strDisplayCharsets
End Function
' End Functions
#Bob77's answer did not work for me, so I converted #Ciove's answer to a simple sub routine and it works fine.
' Usage:
' EncodeFile strInFile, "UTF-8", strOutFile, "Windows-1254", 2
Sub EncodeFile(strInputFile, strInputCharset, strOutputFile, strOutputCharset, intOverwriteMode)
'5th parameter may take the following values:
'Const adSaveCreateOverWrite = 2
'Const adSaveCreateNotExist = 1
Const adReadLine = -2
Const adTypeBinary = 1
Const adTypeText = 2
Const adWriteLine = 1
Set objInputStream = CreateObject("ADODB.Stream")
Set objOutputStream = CreateObject("ADODB.Stream")
With objInputStream
.Open
.Type = adTypeBinary
.LoadFromFile strInputFile
.Type = adTypeText
.Charset = strInputCharset
objOutputStream.Open
objOutputStream.Charset = strOutputCharset
Do While .EOS <> True
strText = .ReadText(adReadLine)
objOutputStream.WriteText strText, adWriteLine
Loop
.Close
End With
objOutputStream.SaveToFile strOutputFile, intOverwriteMode
objOutputStream.Close
End Sub
For various reasons, I'm stuck in Access 97 and need to get only the path part of a full pathname.
For example, the name
c:\whatever dir\another dir\stuff.mdb
should become
c:\whatever dir\another dir\
This site has some suggestions on how to do it:
http://www.ammara.com/access_image_faq/parse_path_filename.html
But they seem rather hideous. There must be a better way, right?
You can do something simple like: Left(path, InStrRev(path, "\"))
Example:
Function GetDirectory(path)
GetDirectory = Left(path, InStrRev(path, Application.PathSeparator))
End Function
I always used the FileSystemObject for this sort of thing. Here's a little wrapper function I used. Be sure to reference the Microsoft Scripting Runtime.
Function StripFilename(sPathFile As String) As String
'given a full path and file, strip the filename off the end and return the path
Dim filesystem As New FileSystemObject
StripFilename = filesystem.GetParentFolderName(sPathFile) & "\"
Exit Function
End Function
This seems to work. The above doesn't in Excel 2010.
Function StripFilename(sPathFile As String) As String
'given a full path and file, strip the filename off the end and return the path
Dim filesystem As Object
Set filesystem = CreateObject("Scripting.FilesystemObject")
StripFilename = filesystem.GetParentFolderName(sPathFile) & "\"
Exit Function
End Function
If you're just needing the path of the MDB currently open in the Access UI, I'd suggest writing a function that parses CurrentDB.Name and then stores the result in a Static variable inside the function. Something like this:
Public Function CurrentPath() As String
Dim strCurrentDBName As String
Static strPath As String
Dim i As Integer
If Len(strPath) = 0 Then
strCurrentDBName = CurrentDb.Name
For i = Len(strCurrentDBName) To 1 Step -1
If Mid(strCurrentDBName, i, 1) = "\" Then
strPath = Left(strCurrentDBName, i)
Exit For
End If
Next
End If
CurrentPath = strPath
End Function
This has the advantage that it only loops through the name one time.
Of course, it only works with the file that's open in the user interface.
Another way to write this would be to use the functions provided at the link inside the function above, thus:
Public Function CurrentPath() As String
Static strPath As String
If Len(strPath) = 0 Then
strPath = FolderFromPath(CurrentDB.Name)
End If
CurrentPath = strPath
End Function
This makes retrieving the current path very efficient while utilizing code that can be used for finding the path for any filename/path.
vFilename="C:\Informes\Indicadores\Program\Ind_Cont_PRv.txt"
vDirFile = Replace(vFilename, Dir(vFileName, vbDirectory), "")
' Result=C:\Informes\Indicadores_Contraloria\Programa\Versiones anteriores\
left(currentdb.Name,instr(1,currentdb.Name,dir(currentdb.Name))-1)
The Dir function will return only the file portion of the full path. Currentdb.Name is used here, but it could be any full path string.
If you are confident in your input parameters, you can use this single line of code which uses the native Split and Join functions and Excel native Application.pathSeparator.
Split(Join(Split(strPath, "."), Application.pathSeparator), Application.pathSeparator)
If you want a more extensive function, the code below is tested in Windows and should also work on Mac (though not tested). Be sure to also copy the supporting function GetPathSeparator, or modify the code to use Application.pathSeparator. Note, this is a first draft; I should really refactor it to be more concise.
Private Sub ParsePath2Test()
'ParsePath2(DrivePathFileExt, -2) returns a multi-line string for debugging.
Dim p As String, n As Integer
Debug.Print String(2, vbCrLf)
If True Then
Debug.Print String(2, vbCrLf)
Debug.Print ParsePath2("", -2)
Debug.Print ParsePath2("C:", -2)
Debug.Print ParsePath2("C:\", -2)
Debug.Print ParsePath2("C:\Windows", -2)
Debug.Print ParsePath2("C:\Windows\notepad.exe", -2)
Debug.Print ParsePath2("C:\Windows\SysWOW64", -2)
Debug.Print ParsePath2("C:\Windows\SysWOW64\", -2)
Debug.Print ParsePath2("C:\Windows\SysWOW64\AcLayers.dll", -2)
Debug.Print ParsePath2("C:\Windows\SysWOW64\.fakedir", -2)
Debug.Print ParsePath2("C:\Windows\SysWOW64\fakefile.ext", -2)
End If
If True Then
Debug.Print String(1, vbCrLf)
Debug.Print ParsePath2("\Windows", -2)
Debug.Print ParsePath2("\Windows\notepad.exe", -2)
Debug.Print ParsePath2("\Windows\SysWOW64", -2)
Debug.Print ParsePath2("\Windows\SysWOW64\", -2)
Debug.Print ParsePath2("\Windows\SysWOW64\AcLayers.dll", -2)
Debug.Print ParsePath2("\Windows\SysWOW64\.fakedir", -2)
Debug.Print ParsePath2("\Windows\SysWOW64\fakefile.ext", -2)
End If
If True Then
Debug.Print String(1, vbCrLf)
Debug.Print ParsePath2("Windows\notepad.exe", -2)
Debug.Print ParsePath2("Windows\SysWOW64", -2)
Debug.Print ParsePath2("Windows\SysWOW64\", -2)
Debug.Print ParsePath2("Windows\SysWOW64\AcLayers.dll", -2)
Debug.Print ParsePath2("Windows\SysWOW64\.fakedir", -2)
Debug.Print ParsePath2("Windows\SysWOW64\fakefile.ext", -2)
Debug.Print ParsePath2(".fakedir", -2)
Debug.Print ParsePath2("fakefile.txt", -2)
Debug.Print ParsePath2("fakefile.onenote", -2)
Debug.Print ParsePath2("C:\Personal\Workspace\Code\PythonVenvs\xlwings_test\.idea", -2)
Debug.Print ParsePath2("Windows", -2) ' Expected to raise error 52
End If
If True Then
Debug.Print String(2, vbCrLf)
Debug.Print "ParsePath2 ""\Windows\SysWOW64\fakefile.ext"" with different ReturnType values"
Debug.Print , "{empty}", "D", ParsePath2("Windows\SysWOW64\fakefile.ext")(1)
Debug.Print , "0", "D", ParsePath2("Windows\SysWOW64\fakefile.ext", 0)(1)
Debug.Print , "1", "ext", ParsePath2("Windows\SysWOW64\fakefile.ext", 1)
Debug.Print , "10", "file", ParsePath2("Windows\SysWOW64\fakefile.ext", 10)
Debug.Print , "11", "file.ext", ParsePath2("Windows\SysWOW64\fakefile.ext", 11)
Debug.Print , "100", "path", ParsePath2("Windows\SysWOW64\fakefile.ext", 100)
Debug.Print , "110", "path\file", ParsePath2("Windows\SysWOW64\fakefile.ext", 110)
Debug.Print , "111", "path\file.ext", ParsePath2("Windows\SysWOW64\fakefile.ext", 111)
Debug.Print , "1000", "D", ParsePath2("Windows\SysWOW64\fakefile.ext", 1000)
Debug.Print , "1100", "D:\path", ParsePath2("Windows\SysWOW64\fakefile.ext", 1100)
Debug.Print , "1110", "D:\p\file", ParsePath2("Windows\SysWOW64\fakefile.ext", 1110)
Debug.Print , "1111", "D:\p\f.ext", ParsePath2("Windows\SysWOW64\fakefile.ext", 1111)
On Error GoTo EH:
' This is expected to presetn an error:
p = "Windows\SysWOW64\fakefile.ext"
n = 1010
Debug.Print "1010", "D:\p\file.ext", ParsePath2("Windows\SysWOW64\fakefile.ext", 1010)
On Error GoTo 0
End If
Exit Sub
EH:
Debug.Print , CStr(n), "Error: "; Err.Number, Err.Description
Resume Next
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Public Function ParsePath2(ByVal DrivePathFileExt As String _
, Optional ReturnType As Integer = 0)
' Writen by Chris Advena. You may modify and use this code provided you leave
' this credit in the code.
' Parses the input DrivePathFileExt string into individual components (drive
' letter, folders, filename and extension) and returns the portions you wish
' based on ReturnType.
' Returns either an array of strings (ReturnType = 0) or an individual string
' (all other defined ReturnType values).
'
' Parameters:
' DrivePathFileExt: The full drive letter, path, filename and extension
' ReturnType: -2 or a string up of to 4 ones with leading or lagging zeros
' (e.g., 0001)
' -2: special code for debugging use in ParsePath2Test().
' Results in printing verbose information to the Immediate window.
' 0: default: Array(driveStr, pathStr, fileStr, extStr)
' 1: extension
' 10: filename stripped of extension
' 11: filename.extension, excluding drive and folders
' 100: folders, excluding drive letter filename and extension
' 111: folders\filename.extension, excluding drive letter
' 1000: drive leter only
' 1100: drive:\folders, excluding filename and extension
' 1110: drive:\folders\filename, excluding extension
' 1010, 0101, 1001: invalid ReturnTypes. Will result raise error 380, Value
' is not valid.
Dim driveStr As String, pathStr As String
Dim fileStr As String, extStr As String
Dim drivePathStr As String
Dim pathFileExtStr As String, fileExtStr As String
Dim s As String, cnt As Integer
Dim i As Integer, slashStr As String
Dim dotLoc As Integer, slashLoc As Integer, colonLoc As Integer
Dim extLen As Integer, fileLen As Integer, pathLen As Integer
Dim errStr As String
DrivePathFileExt = Trim(DrivePathFileExt)
If DrivePathFileExt = "" Then
fileStr = ""
extStr = ""
fileExtStr = ""
pathStr = ""
pathFileExtStr = ""
drivePathStr = ""
GoTo ReturnResults
End If
' Determine if Dos(/) or UNIX(\) slash is used
slashStr = GetPathSeparator(DrivePathFileExt)
' Find location of colon, rightmost slash and dot.
' COLON: colonLoc and driveStr
colonLoc = 0
driveStr = ""
If Mid(DrivePathFileExt, 2, 1) = ":" Then
colonLoc = 2
driveStr = Left(DrivePathFileExt, 1)
End If
#If Mac Then
pathFileExtStr = DrivePathFileExt
#Else ' Windows
pathFileExtStr = ""
If Len(DrivePathFileExt) > colonLoc _
Then pathFileExtStr = Mid(DrivePathFileExt, colonLoc + 1)
#End If
' SLASH: slashLoc, fileExtStr and fileStr
' Find the rightmost path separator (Win backslash or Mac Fwdslash).
slashLoc = InStrRev(DrivePathFileExt, slashStr, -1, vbBinaryCompare)
' DOT: dotLoc and extStr
' Find rightmost dot. If that dot is not part of a relative reference,
' then set dotLoc. dotLoc is meant to apply to the dot before an extension,
' NOT relative path reference dots. REl ref dots appear as "." or ".." at
' the very leftmost of the path string.
dotLoc = InStrRev(DrivePathFileExt, ".", -1, vbTextCompare)
If Left(DrivePathFileExt, 1) = "." And dotLoc <= 2 Then dotLoc = 0
If slashLoc + 1 = dotLoc Then
dotLoc = 0
If Len(extStr) = 0 And Right(pathFileExtStr, 1) <> slashStr _
Then pathFileExtStr = pathFileExtStr & slashStr
End If
#If Not Mac Then
' In windows, filenames cannot end with a dot (".").
If dotLoc = Len(DrivePathFileExt) Then
s = "Error in FileManagementMod.ParsePath2 function. " _
& "DrivePathFileExt " & DrivePathFileExt _
& " cannot end iwth a dot ('.')."
Err.Raise 52, "FileManagementMod.ParsePath2", s
End If
#End If
' extStr
extStr = ""
If dotLoc > 0 And (dotLoc < Len(DrivePathFileExt)) _
Then extStr = Mid(DrivePathFileExt, dotLoc + 1)
' fileExtStr
fileExtStr = ""
If slashLoc > 0 _
And slashLoc < Len(DrivePathFileExt) _
And dotLoc > slashLoc Then
fileExtStr = Mid(DrivePathFileExt, slashLoc + 1)
End If
' Validate the input: DrivePathFileExt
s = ""
#If Mac Then
If InStr(1, DrivePathFileExt, ":") > 0 Then
s = "DrivePathFileExt ('" & DrivePathFileExt _
& "')has invalid format. " _
& "UNIX/Mac filenames cannot contain a colon ('.')."
End If
#End If
If Not colonLoc = 0 And slashLoc = 0 And dotLoc = 0 _
And Left(DrivePathFileExt, 1) <> slashStr _
And Left(DrivePathFileExt, 1) <> "." Then
s = "DrivePathFileExt ('" & DrivePathFileExt _
& "') has invalid format. " _
& "Good example: 'C:\folder\file.txt'"
ElseIf colonLoc <> 0 And colonLoc <> 2 Then
' We are on Windows and there is a colon; it can only be
' in position 2.
s = "DrivePathFileExt ('" & DrivePathFileExt _
& "') has invalid format. " _
& "In the Windows operating system, " _
& "a colon (':') can only be the second character '" _
& "of a valid file path. "
ElseIf Left(DrivePathFileExt, 1) = ":" _
Or InStr(3, DrivePathFileExt, ":", vbTextCompare) > 0 Then
'If path contains a drive letter, it must contain at least one slash.
s = "DrivePathFileExt ('" & DrivePathFileExt _
& "') has invalid format. " _
& "Colon can only appear in the second character position." _
& slashStr & "')."
ElseIf colonLoc > 0 And slashLoc = 0 _
And Len(DrivePathFileExt) > 2 Then
'If path contains a drive letter, it must contain at least one slash.
s = "DrivePathFileExt ('" & DrivePathFileExt _
& "') has invalid format. " _
& "The last dot ('.') cannot be before the last file separator '" _
& slashStr & "')."
ElseIf colonLoc = 2 _
And InStr(1, DrivePathFileExt, slashStr, vbTextCompare) = 0 _
And Len(DrivePathFileExt) > 2 Then
' There is a colon, but no file separator (slash). This is invalid.
s = "DrivePathFileExt ('" & DrivePathFileExt _
& "') has invalid format. " _
& "If a drive letter is included, then there must be at " _
& "least one file separator character ('" & slashStr & "')."
ElseIf Len(driveStr) > 0 And Len(DrivePathFileExt) > 2 And slashLoc = 0 Then
' If path contains a drive letter and is more than 2 character long
' (e.g., 'C:'), it must contain at least one slash.
s = "DrivePathFileExt cannot contain a drive letter but no path separator."
End If
If Len(s) > 0 Then
End If
' Determine if DrivePathFileExt = DrivePath
' or = Path (with no fileStr or extStr components).
If Right(DrivePathFileExt, 1) = slashStr _
Or slashLoc = 0 _
Or dotLoc = 0 _
Or (dotLoc > 0 And dotLoc <= slashLoc + 1) Then
' If rightmost character is the slashStr, then no fileExt exists, just drivePath
' If no dot found, then no extension. Assume a folder is after the last slashstr,
' not a filename.
' If a dot is found (extension exists),
' If a rightmost dot appears one-char to the right of the rightmost slash
' or anywhere before (left) of that, it is not a file/ext separator. Exmaple:
' 'C:\folder1\.folder2' Then
' If no slashes, then no fileExt exists. It must just be a driveletter.
' DrivePathFileExt contains no file or ext name.
fileStr = ""
extStr = ""
fileExtStr = ""
pathStr = pathFileExtStr
drivePathStr = DrivePathFileExt
GoTo ReturnResults
Else
' fileStr
fileStr = ""
If slashLoc > 0 Then
If Len(extStr) = 0 Then
fileStr = fileExtStr
Else
' length of filename excluding dot and extension.
i = Len(fileExtStr) - Len(extStr) - 1
fileStr = Left(fileExtStr, i)
End If
Else
s = "Error in FileManagementMod.ParsePath2 function. " _
& "*** Unhandled scenario: find fileStr when slashLoc = 0. *** "
Err.Raise 52, "FileManagementMod.ParsePath2", s
End If
' pathStr
pathStr = ""
' length of pathFileExtStr excluding fileExt.
i = Len(pathFileExtStr) - Len(fileExtStr)
pathStr = Left(pathFileExtStr, i)
' drivePathStr
drivePathStr = ""
' length of DrivePathFileExt excluding dot and extension.
i = Len(DrivePathFileExt) - Len(fileExtStr)
drivePathStr = Left(DrivePathFileExt, i)
End If
ReturnResults:
' ReturnType uses a 4-digit binary code: dpfe = drive path file extension,
' where 1 = return in array and 0 = do not return in array
' -2, and 0 are special cases that do not follow the code.
' Note: pathstr is determined with the tailing slashstr
If Len(drivePathStr) > 0 And Right(drivePathStr, 1) <> slashStr _
Then drivePathStr = drivePathStr & slashStr
If Len(pathStr) > 0 And Right(pathStr, 1) <> slashStr _
Then pathStr = pathStr & slashStr
#If Not Mac Then
' Including this code add a slash to the beginnning where missing.
' the downside is that it would create an absolute path where a
' sub-path of the current folder is intended.
'If colonLoc = 0 Then
' If Len(drivePathStr) > 0 And Not IsIn(Left(drivePathStr, 1), slashStr, ".") _
Then drivePathStr = slashStr & drivePathStr
' If Len(pathStr) > 0 And Not IsIn(Left(pathStr, 1), slashStr, ".") _
Then pathStr = slashStr & pathStr
' If Len(pathFileExtStr) > 0 And Not IsIn(Left(pathFileExtStr, 1), slashStr, ".") _
Then pathFileExtStr = slashStr & pathFileExtStr
'End If
#End If
Select Case ReturnType
Case -2 ' used for ParsePath2Test() only.
ParsePath2 = "DrivePathFileExt " _
& CStr(Nz(DrivePathFileExt, "{empty string}")) _
& vbCrLf & " " _
& "-------------- -----------------------------------------" _
& vbCrLf & " " & "D:\Path\ " & drivePathStr _
& vbCrLf & " " & "\path[\file.ext] " & pathFileExtStr _
& vbCrLf & " " & "\path\ " & pathStr _
& vbCrLf & " " & "file.ext " & fileExtStr _
& vbCrLf & " " & "file " & fileStr _
& vbCrLf & " " & "ext " & extStr _
& vbCrLf & " " & "D " & driveStr _
& vbCrLf & vbCrLf
' My custom debug printer prints to Immediate winodw and log file.
' Dbg.Prnt 2, ParsePath2
Debug.Print ParsePath2
Case 1 '0001: ext
ParsePath2 = extStr
Case 10 '0010: file
ParsePath2 = fileStr
Case 11 '0011: file.ext
ParsePath2 = fileExtStr
Case 100 '0100: path
ParsePath2 = pathStr
Case 110 '0110: (path, file)
ParsePath2 = pathStr & fileStr
Case 111 '0111:
ParsePath2 = pathFileExtStr
Case 1000
ParsePath2 = driveStr
Case 1100
ParsePath2 = drivePathStr
Case 1110
ParsePath2 = drivePathStr & fileStr
Case 1111
ParsePath2 = DrivePathFileExt
Case 1010, 101, 1001
s = "Error in FileManagementMod.ParsePath2 function. " _
& "Value of Paramter (ReturnType = " _
& CStr(ReturnType) & ") is not valid."
Err.Raise 380, "FileManagementMod.ParsePath2", s
Case Else ' default: 0
ParsePath2 = Array(driveStr, pathStr, fileStr, extStr)
End Select
End Function
Supporting function GetPathSeparatorTest extends the native Application.pathSeparator (or bypasses when needed) to work on Mac and Win. It can also takes an optional path string and will try to determine the path separator used in the string (favoring the OS native path separator).
Private Sub GetPathSeparatorTest()
Dim s As String
Debug.Print "GetPathSeparator(s):"
Debug.Print "s not provided: ", GetPathSeparator
s = "C:\folder1\folder2\file.ext"
Debug.Print "s = "; s, GetPathSeparator(DrivePathFileExt:=s)
s = "C:/folder1/folder2/file.ext"
Debug.Print "s = "; s, GetPathSeparator(DrivePathFileExt:=s)
End Sub
Function GetPathSeparator(Optional DrivePathFileExt As String = "") As String
' by Chris Advena
' Finds the path separator from a string, DrivePathFileExt.
' If DrivePathFileExt is not provided, return the operating system path separator
' (Windows = backslash, Mac = forwardslash).
' Mac/Win compatible.
' Initialize
Dim retStr As String: retStr = ""
Dim OSSlash As String: OSSlash = ""
Dim OSOppositeSlash As String: OSOppositeSlash = ""
Dim PathFileExtSlash As String
GetPathSeparator = ""
retStr = ""
' Determine if OS expects fwd or back slash ("/" or "\").
On Error GoTo EH
OSSlash = Application.pathSeparator
If DrivePathFileExt = "" Then
' Input parameter DrivePathFileExt is empty, so use OS file separator.
retStr = OSSlash
Else
' Input parameter DrivePathFileExt provided. See if it contains / or \.
' Set OSOppositeSlash to the opposite slash the OS expects.
OSOppositeSlash = "\"
If OSSlash = "\" Then OSOppositeSlash = "/"
' If DrivePathFileExt does NOT contain OSSlash
' and DOES contain OSOppositeSlash, return OSOppositeSlash.
' Otherwise, assume OSSlash is correct.
retStr = OSSlash
If InStr(1, DrivePathFileExt, OSSlash, vbTextCompare) = 0 _
And InStr(1, DrivePathFileExt, OSOppositeSlash, vbTextCompare) > 0 Then
retStr = OSOppositeSlash
End If
End If
GetPathSeparator = retStr
Exit Function
EH:
' Application.PathSeparator property does not exist in Access,
' so get it the slightly less easy way.
#If Mac Then ' Application.PathSeparator doesn't seem to exist in Access...
OSSlash = "/"
#Else
OSSlash = "\"
#End If
Resume Next
End Function
Supporting function (actually commented out, so you can skip this if you don't plan to use it).
Sub IsInTest()
' IsIn2 is case insensitive
Dim StrToFind As String, arr As Variant
arr = Array("Me", "You", "Dog", "Boo")
StrToFind = "doG"
Debug.Print "Is '" & CStr(StrToFind) & "' in list (expect True): " _
, IsIn(StrToFind, "Me", "You", "Dog", "Boo")
StrToFind = "Porcupine"
Debug.Print "Is '" & CStr(StrToFind) & "' in list (expect False): " _
, IsIn(StrToFind, "Me", "You", "Dog", "Boo")
End Sub
Function IsIn(ByVal StrToFind, ParamArray StringArgs() As Variant) As Boolean
' StrToFind: the string to find in the list of StringArgs()
' StringArgs: 1-dimensional array containing string values.
' Built for Strings, but actually works with other data types.
Dim arr As Variant
arr = StringArgs
IsIn = Not IsError(Application.Match(StrToFind, arr, False))
End Function
Try this function:
Function FolderPath(FilePath As String) As String
'--------------------------------------------------
'Returns the folder path form the file path.
'Written by: Christos Samaras
'Date: 06/11/2013
'--------------------------------------------------
Dim FileName As String
With WorksheetFunction
FileName = Mid(FilePath, .Find("*", .Substitute(FilePath, "\", "*", Len(FilePath) - _
Len(.Substitute(FilePath, "\", "")))) + 1, Len(FilePath))
End With
FolderPath = Left(FilePath, Len(FilePath) - Len(FileName) - 1)
End Function
If you don't want to remove the last backslash "\" at the end of the folder's path, change the last line with this:
FolderPath = Left(FilePath, Len(FilePath) - Len(FileName))
Example:
FolderPath("C:\Users\Christos\Desktop\LAT Analysers Signal Correction\1\TP 14_03_2013_5.csv")
gives:
C:\Users\Christos\Desktop\LAT Analysers Signal Correction\1
or
C:\Users\Christos\Desktop\LAT Analysers Signal Correction\1\
in the second case (note that there is a backslash at the end).
I hope it helps...
Use these codes and enjoy it.
Public Function GetDirectoryName(ByVal source As String) As String()
Dim fso, oFolder, oSubfolder, oFile, queue As Collection
Set fso = CreateObject("Scripting.FileSystemObject")
Set queue = New Collection
Dim source_file() As String
Dim i As Integer
queue.Add fso.GetFolder(source) 'obviously replace
Do While queue.Count > 0
Set oFolder = queue(1)
queue.Remove 1 'dequeue
'...insert any folder processing code here...
For Each oSubfolder In oFolder.SubFolders
queue.Add oSubfolder 'enqueue
Next oSubfolder
For Each oFile In oFolder.Files
'...insert any file processing code here...
'Debug.Print oFile
i = i + 1
ReDim Preserve source_file(i)
source_file(i) = oFile
Next oFile
Loop
GetDirectoryName = source_file
End Function
And here you can call function:
Sub test()
Dim s
For Each s In GetDirectoryName("C:\New folder")
Debug.Print s
Next
End Sub