I could use some help in troubleshooting my code, which should run a report based on files in a folder, which meet certain criteria, read specific lines from those files and sum all the read values. And do some math later on.
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set WshShell = CreateObject("WScript.Shell")
relativePath = wshShell.CurrentDirectory
Set ReportPath = objFSO.GetFolder(relativePath & "\KPI_STATS\")
count = 0
Now I'd like to check each file's filename in ReportPath if it matches current month...
For Each file In ReportPath.files
If instr(LCase(file.name), LCase(Right("0" & DatePart("m",Now),2))) > 0 Then
for i=0 to n
SIDENOTE: Now I don't understand why if I run msgbox(file) for testing only it gives me whole path to the folder with filename instead of filename only.
(let's continue)...and when it does, it should read only 14th line of text (last line and there are only numbers in it) of each file and store it in variable. I use Split for reading certain lines from files and arrays to hold read values but I can use as well something like sum = sum + sum(n-1).
a = Split(objFSO.OpenTextFile(file, ForReading).ReadAll, vbCrLf)
For j = 14
If UBound(a) = j Then
And now I'd like to write those values to separate Arrays
ar(i) = Array(a(j))
End If
Next
next
count = count + 1
End If
Next
I think I will manage to add and divide all the values as soon as I have all arrays in place but there i a problem. It doesn't work :'(
Thanks a lot.
Related
(I'm quite new to vb, but familiar with vba).
I'm trying to find out how to read a text file from bottom to top as:
the text file is updated 'x' period of time; lines being added,
and I need to find the last entry "line" that contains the contains the text "System Pass". However between the last line of the file and the last line that contains the needed string are a lot unnecessary "dump" lines.
With excel I used to import the text file and loop through the rows starting at the bottom and to determine if I had the correct string line with the inStr function. But this doesn't work, or I just simply don't know how to convert the code to vb.
Help is greatly appreciated.
Thanks
Philippe
Here is an example of how to read a txt file into an array and poll through it from bottom to top using instr to search for text:
Const ForReading = 1
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTextFile = objFSO.OpenTextFile("c:\temp\test.txt", ForReading)
strText = objTextFile.ReadAll
objTextFile.Close
MyArray = Split(strText, vbCrLf)
For X = Ubound(MyArray) to lbound(MyArray) step -1
If instr(1,MyArray(X),"T") > 0 then
Wscript.Echo MyArray(X)
End if
Next
My Test file contained this:
hello
World
This
Is
Text
The VBS file popped up 2 message boxes, one with "Text" and one with "This"
You can DIM them if you want:
Dim objFSO
Dim objTextFile
Dim X
Dim MyArray
But VBS doesn't support types so don't try Dim X as Long or anything like that.
Hope that helps
I recommend import the data with Excel, you can use NPOI library, with NPOI you can easily read Excel files in .NET.
EDIT:
Read txt files with VB: https://msdn.microsoft.com/en-us/library/yw67h925.aspx
I am trying to split a tab delemeted file into pieces with similar header. I have my logic in place. However, I am trying to read input file line by line and writing it to another file. When I open the outptut file it doesn't contain any data. Here is my code.
Can some one help me whats going wrong here?
Note: The below code doesn't contain actual logic of splitting the file
Wscript.Echo "Begin"
InputFile = "test.txt"
Set InputFSO = CreateObject("Scripting.FileSystemObject")
Set InputFileObject = InputFSO.OpenTextFile(InputFile)
HeaderLine = InputFileObject.ReadLine
Do While InputFileObject.AtEndOfStream <> True
strTemp = InputFileObject.SkipLine
Loop
TotalLines = InputFileObject.Line-1
Set OutputFSO = CreateObject("Scripting.FileSystemObject")
Set OutputFileObject = OutputFSO.CreateTextFile("out.txt")
#Code for reading line by line and writing it to another file
Do While not InputFileObject.AtEndOfStream
line = InputFileObject.Readline
OutputFileObject.WriteLine(line)
Loop
Set InputFileObject = Nothing
Set OutputFileObject = Nothing
Wscript.Echo "Completed"
You're looping through the entire input file in the first Do loop when you are trying to get the line count. So the InputFileObject is already "AtEndOfStream" when you hit the second Do loop. Therefore, none of the code inside the second loop is executing.
Consider eliminating the first Do loop and count the lines in the file at the end of the other loop (unless in your real program the logic in the first loop is required?).
The alternative is to close the input file and reopen it. The problem in this case is that you'll wind up reading the file twice.
'Close and reopen the file from the top...
InputFileObject.Close
Set InputFileObject = InputFSO.OpenTextFile(InputFile)
I was googling around but didn't find the right answer, perhaps people from here are willingly and able to help me.
I'm very new to VBS or WSH and I like to have a solution for this problem:
I'm searching for textstrings within a file without a line break (only one line). The textstrings I'm looking for start always with the same content "jpgline" and ends with the three letters "qbm". How can we extract each sentence (the strings are always 64 chars long) containg "jpgline....qbm" into a separate file.
I'm looking for a solution in Visual Basic Script as I use Windows 7.
Thanks in advance
M i k e
Use a regular expression:
Set re = New RegExp
re.Pattern = "^jpgline.*qbm$"
re.IgnoreCase = True
Set fso = CreateObject("Scripting.FileSystemObject")
Set inFile = fso.OpenTextFile("C:\path\to\input.txt")
Set outFile = fso.OpenTextFile("C:\path\to\output.txt", 2, True)
Do Until inFile.AtEndOfStream
line = inFile.ReadLine
If re.Test(line) Then outFile.WriteLine line
Loop
inFile.Close
outFile.Close
As your input file has no lines, use .ReadAll() to load its entire content into a string variable. Apply a RegExp to get all parts (Matches) defined by the pattern "jpgline.{N}qbm" where N is either 64 or 64 - the length of the pre/suffix. Ansgar has shown how to open and write to the output file.
Use the RegExp Docs to learn about .Execute and how to loop over the resulting match collection. The docs will tell you about .Test too.
I am not sure if this is possible or not. I am not even sure where to begin. I have a couple thousand files where the file names are named as so:
nnnnnnnnnnnnnnnn.yyyyddmm.pdf (n = number, yyyy = year, dd = day, and mm = month).
Within these thousands of files, there are batches of alike files that have the same nnnnnnnnnnnnnnnnnn part of the filename but the .yyyyddmm is different in order to represent the date of the file. (These batches of alike files will be merged together at a later point but that is not important to this scenario).
My question is, Is there a way to compare the yyyyddmm part of the alike files and have the most recent date files get copied to a different folder? I need the file that has the most recent date of the alike files on the filename get copied to a different folder.
The reason that I am having issues with this is because I am not sure if it is possible to compare parts of the filename to see which one is in fact the file that has the most recent date. I know that there is a way that this can be done through looking at the date modified date but this will not always give me the alike file with the most recent date.
Any thoughts?? Please let me know if I could provide more information.
Trying to understand your problem/specs. Assume a loop over the files of your .pdf folder results in:
Looking at "0000000000012345.20120402.pdf"
Looking at "0000000000012345.20120502.pdf"
Looking at "0000000000012348.20121702.pdf"
Looking at "0000000000012346.20120802.pdf"
Looking at "0000000000012347.20121002.pdf"
Looking at "0000000000012348.20121602.pdf"
Looking at "0000000000012347.20121302.pdf"
Looking at "0000000000012347.20121202.pdf"
Looking at "0000000000012345.20120202.pdf"
Looking at "0000000000012348.20121502.pdf"
Looking at "0000000000012346.20120602.pdf"
Looking at "0000000000012346.20120902.pdf"
Looking at "0000000000012348.20121402.pdf"
Looking at "0000000000012346.20120702.pdf"
Looking at "0000000000012347.20121102.pdf"
Looking at "0000000000012345.20120302.pdf"
Would
Last file for 0000000000012345 is 0000000000012345.20120502.pdf
Last file for 0000000000012348 is 0000000000012348.20121702.pdf
Last file for 0000000000012346 is 0000000000012346.20120902.pdf
Last file for 0000000000012347 is 0000000000012347.20121302.pdf
identify the files to copy correctly? If yes, say so and I will post the code here.
First, you need a class to obtain and store the info put into the file names:
' cut & store info about file(names) like "0000000000012347.20121202.pdf"
Class cCut
Private m_sN ' complete file name
Private m_sG ' group/number prefix part
Private m_dtF ' date part; converted to ease comparisons
Public Function cut(reCut, sFiNa)
Set cut = Me ' return self/this from function
Dim oMTS : Set oMTS = reCut.Execute(sFiNa)
If 1 = oMTS.Count Then
m_sN = sFiNa
Dim oSM : Set oSM = oMTS(0).SubMatches
m_sG = oSM(0)
m_dtF = DateSerial(oSM(1), oSM(3), oSM(2))
Else
' Err.Raise
End If
End Function ' cut
Public Property Get G() : G = m_sG : End Property ' G
Public Property Get D() : D = m_dtF : End Property ' D
Public Property Get N() : N = m_sN : End Property ' N
End Class ' cCut
Then just loop over the .Files and check the date parts for each group stored in a dictionary (number prefix part used as key):
' The one and only .pdf folder - no recursion into subfolders!
Dim sTDir : sTDir = "..\data\test"
' dictionary to store the last/most recently used file for each group
Dim dicG : Set dicG = CreateObject("Scripting.Dictionary")
' RegExp to cut/parse file names like "0000000000012345.20120402.pdf"
Dim reCut : Set reCut = New RegExp
reCut.Pattern = "^(\d{16})\.(\d{4})(\d{2})(\d{2})\.pdf$"
Dim oFile
For Each oFile In goFS.GetFolder(sTDir).Files
WScript.Echo "Looking at", qq(oFile.Name)
' an oCut object for each file name
Dim oCut : Set oCut = New cCut.cut(reCut, oFile.Name)
If Not dicG.Exists(oCut.G) Then
' new group, first file, assume this is the latest
Set dicG(oCut.G) = oCut
Else
' found a better one for this group?
If dicG(oCut.G).D < oCut.D Then Set dicG(oCut.G) = oCut
End If
Next
WScript.Echo "-----------------------"
Dim sG
For Each sG In dicG.Keys
WScript.Echo "Last file for", sG, "is", dicG(sG).N
Next
WRT comments:
All my (ad hoc/proof of concept) scripts start with
Option Explicit
Dim goFS : Set goFS = CreateObject( "Scripting.FileSystemObject" )
and contain some functions dealing with different aspects/stragegies for a solution to a common problem/topic. When I post code here, I copy/paste working/tested code out of the middle of a function frame like
' ============================================================================
goXPLLib.Add _
"useDic02", "use a dictionary (Mark II)"
' ----------------------------------------------------------------------------
' ============================================================================
Function useDic02()
useDic02 = 1 ' assume error
' The one and only .pdf folder - no recursion into subfolders!
...
Next
useDic02 = 0 ' success
End Function ' useDic02
(yes, there is a first attempt function "useDic()" that was guilty of storing all the oCuts for each group to be processed in a second loop; yes, there is a function "createTestData()" I needed to set up/fill my TDir). Sometimes I'm sloppy and forget about goFS, please accept my apologies.
The variable names are part of an experiment. I used to advocate type-prefixed long variable names upto and including
Dim nIdx
For nIdx = 0 To UBound(aNames)
aNames(nIdx) = ...
Next
Other people argued that nIdx-alikes variables just add some letters to mistype but no additional meaning over i, and that aNames-alikes can't be understood without the context and if you have that, aN would be a just as good remainder for "The first names of the kings of persia from the currently processed file to be compared to the names in the database".
So I thought: Given that there are 3 interesting aspects of a file name (full name to copy, number prefix to group, date part to compare/decide) and that there is half a screen between
Private m_sN ' complete file name
and
Public Property Get N() : N = m_sN : End Property ' N
and given that you need just those 3 properties of the Cut object to use it in
Dim oCut : Set oCut = New cCut.cut(reCut, oFile.Name)
If Not dicG.Exists(oCut.G) Then
' new group, first file, assume this is the latest
Set dicG(oCut.G) = oCut
Else
' found a better one for this group?
If dicG(oCut.G).D < oCut.D Then Set dicG(oCut.G) = oCut
will the average short time memory cope with oCut.D?
Obviously not.
To copy the selected files:
Assuming you want the files copied to an existing folder "..\data\latest", use
goFS.CopyFile goFS.BuildPath(sTDir, dicG(sG).N), "..\data\latest\", True
instead of/in addition to the line
WScript.Echo "Last file for", sG, "is", dicG(sG).N
I did not anticipate that .CopyFile chokes on relative source pathes; so consider replacing the *N*ame property of the cCut class with a *P*ath property.
Trying to use
dicG(sG).Copy "..\data\latest\", True
results in:
Microsoft VBScript runtime error: Object doesn't support this property or method: 'dicG(...).Copy'
because the objects stored aren't files (which have a .Copy method), but cCuts (which don't).
How I would handle it:
I would make a dictionary with for each unique number part a separate key. The value will be an array with all file names sharing that key (and thus sharing the unique number part)
For each key in the dictionary, I will loop through the items in the array, searching for the most recent date.
Approach:
Get a file
Extract number part
See if a key for that number part exist. If not create a key for that number with an empty array as value
Add the filename as a new item to the array
Loop to 1. until all files are handled
Get a key
Get the first file in the attached array. Remember the date and the arrayindex
Get the next file, if the date is higher than the remembered date, update the date to this date and the arrayindex to this array index
Loop to 8. until the end of the array is reached
Store the file with the arrayindex as the most recent file for that unique number
loop to 6. until all keys are handled
Please find the code:
Problem is the folder has a large no. of files
=====================================================================================
Dim fso, objFolder, obFileList, folderpath,counter
folderpath = "G:\Everyone\Model Office Testing Documents\HP QC\QTP\PSISAutomation\Logs"
Set fso = CreateObject("Scripting.FileSystemObject")
Set objFolder = fso.GetFolder(folderpath)
Set objFileList = objFolder.Files
For Each File In objFileList
msgbox("5")
If InStr(1,File.Name,"DE_For_Pol_Print_APPA_7A_Copy_") = 1 Then
counter=counter+1
End If
Next
counter=counter+1
msgbox("new file will be saved as: " &"DE_For_Pol_Print_APPA_7A_Copy_"& Chr(64 + Counter))
Do not use the FSO, but make use of the WMI where you put the filename in the SELECT statement, like: "DE_For_Pol_Print_APPA_7A_Copy_%". This should return a collection with only files with the requested filename (faster than a total collection).
There is no count property for file collections, but you can use:
For Each file in fileCollection
counter = counter + 1
Next
This will not access the internal file object and should run reasonably fast.
A second and even faster (but uglier imo) technique is to use the command prompt from a windowshell object and return the dir to the output. The output is just a string. Now, count the amount of matches on your desired string (DE_For_Pol_Print_APPA_7A_Copy_) and that is your counter.
The exact code is left blank as an excercise for the poster.