This question already has answers here:
How to save a Unicode character to a text file
(4 answers)
VBA Add row to csv file [closed]
(2 answers)
Closed 1 year ago.
Hello I am working in MS Access VBA
I am writing code to loop through all query defs and append them to a text file.
When the query sql contains utf-8 characters, my output file contains "???" where the UTF-8 characters should appear. I would like the utf-8 characters appear in the text file. My Code is below, any help would be appreciated.
Sub PrintQueries()
Dim strSeparator As String
Dim strFileName As String
Dim returnvalue As Variant
Dim qdef As QueryDef
Dim qdefs As QueryDefs
Dim strQueryName As String
Dim strQuery As String
Dim strdate As String
strdate = Replace(Replace(Now(), "/", "-"), ":", ".")
Set qdefs = Application.CodeDb.QueryDefs
strFileName = "C:\temp\Queries_" & strdate & ".txt"
For Each qdef In qdefs
strQueryName = qdef.Name
If Left(strQueryName, 1) <> "~" Then
Call TxtAppend(strFileName, strQueryName)
strQuery = qdef.SQL '<-- What if strQuery contains utf-8?
Call TxtAppend(strFileName, strQuery) '<-- Call function
strSeparator = "===================="
Call TxtAppend(strFileName, strSeparator)
End If
Next
returnvalue = Shell("notepad.exe" & strFileName, vbNormalFocus)
End Sub
Public Function TxtAppend(strFileName As String, strText As String)
Dim intFileNumber As Integer
intFileNumber = FreeFile
Open strFileName For Append As #intFileNumber
Print #intFileNumber, strText
Close #intFileNumber
End Function
Related
I am trying to open a pdf file through MS Word, perform certain action such as evaluating calculations, printing the files, etc. and then proceed with closing the file. The error message I received is "Microsoft Excel is waiting for another application to complete an OLE action."
I have previously tried hyperlinkfollow and Shell MyPath & " " & MyFile, vbNormalFocus method, it doesn't work. I am still at the starting phase of opening the pdf files, please advice. Thanks!
Sub Extract_PDF_Data()
Dim mainData As String
Dim strFile As String
Dim Oldname As String
Dim Newname As String
Dim Folderpath As String
Dim s As String
Dim t As Excel.Range
Dim wd As New Word.Application
Dim mydoc As Word.Document
Folderpath = InputBox("Folder path: ")
Folderpath = Folderpath & "\"
strFile = Dir(Folderpath & "", vbNormal)
Do While Len(strFile) > 0
Oldname = Folderpath & strFile
Set wd = CreateObject("Word.Application")
Set mydoc = Word.Documents.Open(Filename:=Oldname, Format:="PDF Files",
ConfirmConversions:=False)
mainData = mydoc.Content.Text
mydoc.Close False
wd.Quit
strFile = Dir
Loop
End Sub
Don't us the New keyword in the line that declares the object variable. This will "block" the object variable - it causes the error when the code laters tries to instantiate it. This method can work in VB.NET but not in VBA.
Do it more like this:
Dim wd As Word.Application
Set wd = New Word.Application. 'Or use CreateObject
I think a combination of those three sources will lead to the answer:
How to open a pdf with Excel?
How to extract data from pdf using VBA?
How to open and print a pdf using VBA?
I think it will be something like this:
Sub Extract_PDF_Data()
Dim mainData As String
Dim strFile As String
Dim Oldname As String
Dim Newname As String
Dim Folderpath As String
Dim s As String
Dim t As Excel.Range
Dim Appshell As Variant
Dim ap As String
Dim Browsedir As Variant
Dim f As Variant
Dim KeyWord As String
' This is a suggestion, I use it because it is more convenient than copy-pasting folder paths
Dim FSO As Object
Set FSO = CreateObject("Scripting.Filesystemobject")
' Get Folder over user input
Set Appshell = CreateObject("Shell.Application")
Set Browsedir = Appshell.BrowseForFolder(0, "Select a Folder", &H1000, "E:\Xample\Path")
' check if not cancalled
If Not Browsedir Is Nothing Then
Folderpath = Browsedir.items().Item().Path
Else
GoTo Quit
End If
KeyWord = "The_Materialist_Example"
' go through all files in the folder
For Each f In FSO.GetFolder(Folderpath).Files
' if file is a pdf , open, check for keyword, decide if should be printed
If LCase(Right(f.Name, 3)) = "pdf" Then
' Here the methods suggest different answers.
' You can either use FollowHyperLink or use the Adobe Library to OPEN PDF
' I would write a function that checks the active pdf for the keyword : IsKeyFound
Debug.Print Folderpath & "\" & f.Name
Call PrintPDF(Folderpath & "\" & f.Name)
If IsKeyFound(f, KeyWord) Then
f.Print
End If
End If
Next f
Quit:
End Sub
Private Sub PrintPDF(strPDFFileName As String)
Dim sAdobeReader As String 'This is the full path to the Adobe Reader or Acrobat application on your computer
Dim RetVal As Variant
sAdobeReader = "C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe"
'Debug.Print sAdobeReader & "/P" & Chr(34) & strPDFFileName & Chr(34)
RetVal = Shell(sAdobeReader & " /P " & Chr(34) & strPDFFileName & Chr(34), 0)
End Sub
Private Function IsKeyFound(PDF As Variant, KeyWord As String) As Boolean
'Decide if file needs to be printed, insert your criteria and search algorithm here
End Function
I have not been able to figure out how to extract the keywords, you could however use a user input as a first approach and later move on to a automated scan of the pdf.
I hope this gets you further on the way to the solution.
So we now have the below script. Debug highlights OpenTextfile as highlighted in bold.
Before it is put into the second part of the update script can we confirm somehow that the text has been read.
Function TextFile_PullData()
'PURPOSE: Send All Data From Text File To A String Variable
Dim TextFile As Integer
Dim FilePath As String
Dim FileContent As String
Dim strUser As String
' get the current user name
strUser = CreateObject("WScript.Network").UserName
'or use strUser = CreateObject("WScript.Shell").ExpandEnvironmentStrings("%USERNAME%")
'File Path of Text File
FilePath = "C:\Users\" & strUser & "\Temp\VFile.txt"
'Determine the next file number available for use by the FileOpen function
TextFile = FreeFile
'Open the text file
**Open FilePath For Input As TextFile**
'Store file content inside a variable
FileContent = Input(LOF(TextFile), TextFile)
'Close Text File
Close TextFile
'Report Out Text File Contents
MsgBox FileContent
'have the function return the data to the calling code
TextFile_PullData = FileContent
End Function
Sub UpdateSubject()
Dim SaveCode As String
Dim KeyWord As String
Dim objItem As MailItem
KeyWord = "TSD"
SaveCode = TextFile_PullData
Set objItem = GetCurrentItem()
objItem.Subject = "[" + KeyWord + "=" + SaveCode + "] " + objItem.Subject
End Sub
Function GetCurrentItem() As Object
Dim objApp As Outlook.Application
Set objApp = Application
On Error Resume Next
Select Case TypeName(objApp.ActiveWindow)
Case "Explorer"
Set GetCurrentItem = objApp.ActiveExplorer.Selection.Item(1)
Case "Inspector"
Set GetCurrentItem = objApp.ActiveInspector.CurrentItem
End Select
Set objApp = Nothing
End Function
This is not VBScript because you are defining your variables As <something>. In VBScript all variables are of type variant.
Anyway, your Sub UpdateSubject may very well read in the content of the text file, but is does nothing other than show it in a messagebox.
In order to make it return this data instead of just reading it in a local variable that lives only insife that sub, make it a Function like :
Function TextFile_PullData()
'PURPOSE: Send All Data From Text File To A String Variable
Dim TextFile As Integer
Dim FilePath As String
Dim FileContent As String
Dim strUser As string
' get the current user name
strUser = CreateObject("WScript.Network").UserName
'or use strUser = CreateObject("WScript.Shell").ExpandEnvironmentStrings("%USERNAME%")
'File Path of Text File
FilePath = "C:\Users\" & strUser & "\Temp\VFile.txt"
'Determine the next file number available for use by the FileOpen function
TextFile = FreeFile
'Open the text file
Open FilePath For Input As TextFile
'Store file content inside a variable
FileContent = Input(LOF(TextFile), TextFile)
'Close Text File
Close TextFile
'Report Out Text File Contents
MsgBox FileContent
'have the function return the data to the calling code
TextFile_PullData = FileContent
End Function
Next use that info in the UpdateSubject subroutine
Sub UpdateSubject()
Dim SaveCode As String
Dim KeyWord As String
Dim objItem As MailItem
Dim FileContent As String
' here, you use the function to pull the content of the text file and store it in
' a local variable called 'FileContent' to use in your inputbox.
FileContent = TextFile_PullData
SaveCode = InputBox("Please enter filecode in the format nnn/nnn", "VisualFiles Auto Save", FileContent)
Set objItem = GetCurrentItem()
KeyWord = "TSD"
objItem.Subject = "[" + KeyWord + "=" + SaveCode + "] " + objItem.Subject
'or skip the inputox alltogether and set the subject directly:
'objItem.Subject = "[" + KeyWord + "=" + FileContent + "] " + objItem.Subject
End Sub
This question already has answers here:
Open Excel file for reading with VBA without display
(10 answers)
Closed 5 years ago.
Set ObjWB = Workbooks.Open("c:\Test.xlsx")
If I used workbooks.open command, that Excel workbook opens.
I need without open that Excel workbook to read the cell value.
Run the Sub GetValue after setting the parameters in ReadFromClosedWorkbook (Workbook & Worksheet). You could pass either or both of them as arguments from the calling procedure.
Sub GetValue()
Debug.Print ReadFromClosedWorkbook("A1")
End Sub
Private Function ReadFromClosedWorkbook(Target As String) As Variant
Const WbFullName = "D:\My Documents\Your file name.xlsx"
Dim PathName As String
Dim WbName As String
Dim WsName As String
Dim Target As String
Dim Sp() As String
WsName = "My Worksheet's Name"
Sp = Split(WbFullName, "\")
WbName = Sp(UBound(Sp))
ReDim Preserve Sp(UBound(Sp) - 1)
PathName = Join(Sp, "\") & "\"
If Len(Dir(WbFullName)) Then
Target = "'" & PathName & _
"[" & WbName & "]" & WsName & _
"'!" & Range(Target).Address(True, True, xlR1C1)
ReadFromClosedWorkbook = ExecuteExcel4Macro(Target)
End If
End Function
Filename = Dir(Filepath & "\" & "*.csv")
While Filename <> ""
SourceFile = Filepath & "\" & Filename
TargetFile = SavePath & "\" & Replace(Filename, ".csv", ".txt")
OpenAsUnicode = False
Dim objFSO: Set objFSO = CreateObject("Scripting.FileSystemObject")
'Detect Unicode Files
Dim Stream: Set Stream = objFSO.OpenTextFile(SourceFile, 1, False)
intChar1 = Asc(Stream.Read(1))
intChar2 = Asc(Stream.Read(1))
Stream.Close
If intChar1 = 255 And intChar2 = 254 Then
OpenAsUnicode = True
End If
'Get script content
Set Stream = objFSO.OpenTextFile(SourceFile, 1, 0, OpenAsUnicode)
arrData = Stream.ReadAll()
Stream.Close
'Create output file
Dim objOut: Set objOut = objFSO.CreateTextFile(TargetFile)
objOut.Write Replace(Replace(arrData,",", "#|#"), Chr(34), "") '-- This line is working fine but it is replacing all the commas inside the text qualifier as well..
objOut.Close
Filename = Dir
Wend
In the above code the line objOut.Write Replace(Replace(arrData,",", "#|#"), Chr(34), "") is replacing all the commas with #|# including the commas inside string.so I want to replace only commas which are not in double quotes.
File containing the string
"A","B,C",D
Result I need is
A#|#B,C#|#D
Thanks for your help in advance.
How about something along the line of:
objOut.Write Mid(Replace(Replace(arrData,""",""", "#|#"), Chr(34), ""), 2)
Basically, this exchanges now "," for #|#. But that's not enough as the file begins with a ". So, this one is being eliminated using the Mid() function. If the file also ends with a " then you would have to adjust that as well.
Based on the speed concerns noted in the comments here is the complete code which I used to test this solution:
Option Explicit
Option Compare Text
Public Sub ConvertFile()
Dim lngRowNumber As Long
Dim strLineFromFile As String
Dim strSourceFile As String
Dim strDestinationFile As String
strSourceFile = "C:\tmp\Extract.txt"
strDestinationFile = "C:\tmp\Extract_b.txt"
Open strSourceFile For Input As #1
Open strDestinationFile For Output As #2
lngRowNumber = 0
Do Until EOF(1)
Line Input #1, strLineFromFile
strLineFromFile = Mid(Replace(strLineFromFile, """,""", "#|#"), 2)
Write #2, strLineFromFile
strLineFromFile = vbNullString
Loop
Close #1
Close #2
End Sub
The tested file was 350 MB with a bit over 4 million rows. The code completed in less than a minute.
I have an access database which manipulates data from a Magento e-commerce store, reformats the data and (hopefully!) spits out a CSV file which can then be imported into ebay Turbolister for mass upload to eBay.
I have got as far as creating a query which correctly lays out the data into the format required by Turbolister.
My issues are various (including some which appear to be related to Access' handling of large field contents), however the crux of my problem is that I am struggling to get working a simple script which exports the query results as a properly formatted CSV (including doubling up on double quotes where required inside a text value i.e. if the value itself contains quotes which need to be retained).
The DoCmd.TransferText solution throws an error related to field size ('the field is too small to accept the amount of data you attempted to add') so thats no good.
Has anyone got a good working CSV export routine in VBA that they can suggest?
Cheers
This is an old function I sometimes used to use, it allows you to specify the delimeter, it also checks the data it's outputting and if it can't be evaluated to either a date or a numeric etc, then it uses double quotes:
Public Function ExportTextDelimited(strQueryName As String, strDelimiter As String)
Dim rs As Recordset
Dim strHead As String
Dim strData As String
Dim inti As Integer
Dim intFile As Integer
Dim fso As New FileSystemObject
On Error GoTo Handle_Err
fso.CreateTextFile ("C:\Untitled.csv")
Set rs = Currentdb.OpenRecordset(strQueryName)
rs.MoveFirst
intFile = FreeFile
strHead = ""
'Add the Headers
For inti = 0 To rs.Fields.Count - 1
If strHead = "" Then
strHead = rs.Fields(inti).Name
Else
strHead = strHead & strDelimiter & rs.Fields(inti).Name
End If
Next
Open "C:\Untitled.csv" For Output As #intFile
Print #intFile, strHead
strHead = ""
'Add the Data
While Not rs.EOF
For inti = 0 To rs.Fields.Count - 1
If strData = "" Then
strData = IIf(IsNumeric(rs.Fields(inti).value), rs.Fields(inti).value, IIf(IsDate(rs.Fields(inti).value), rs.Fields(inti).value, """" & rs.Fields(inti).value & """"))
Else
strData = strData & strDelimiter & IIf(IsNumeric(rs.Fields(inti).value), rs.Fields(inti).value, IIf(IsDate(rs.Fields(inti).value), rs.Fields(inti).value, """" & rs.Fields(inti).value & """"))
End If
Next
Print #intFile, strData
strData = ""
rs.MoveNext
Wend
Close #intFile
rs.Close
Set rs = Nothing
'Open the file for viewing
Application.FollowHyperlink "C:\Untitled.csv"
Exit Function
Handle_Err:
MsgBox Err & " - " & Err.Description
End Function
It may need a couple of tweaks as I've taken out some bits which were only relevant to my particular case but this may be a starting point.