Delete lines starting from bottom - vbscript

I got this code which deletes 10 lines starting from the top.
Is it possible to do the same but starting the delete from the bottom to the top of the txt file?
So if I have 30 lines, I want the last 10 or 20 lines to be deleted.
Const FOR_READING = 1
Const FOR_WRITING = 2
strFileName = "C:\scripts\delete.txt"
iNumberOfLinesToDelete = 10
Set objFS = CreateObject("Scripting.FileSystemObject")
Set objTS = objFS.OpenTextFile(strFileName, FOR_READING)
strContents = objTS.ReadAll
objTS.Close
arrLines = Split(strContents, vbNewLine)
Set objTS = objFS.OpenTextFile(strFileName, FOR_WRITING)
For i=0 To UBound(arrLines)
If i > (iNumberOfLinesToDelete - 1) Then
objTS.WriteLine arrLines(i)
End If
Next

If you read the entire file into an array of lines you'd use more or less the same approach for removing lines from beginning or end.
To remove lines from the beginning you start at an offset after the lines that you want removed:
filename = "C:\path\to\your.txt"
numLinesToRemove = 10
Set fso = CreateObject("Scripting.FileSystemObject")
txt = Split(fso.OpenTextFile(filename).ReadAll, vbNewLine)
Set f = fso.OpenTextFile(filename, 2)
For i = numLinesToRemove To UBound(txt)
f.WriteLine txt(i)
Next
f.Close
To remove lines from the end of the file you stop before the lines that you want removed:
filename = "C:\path\to\your.txt"
numLinesToRemove = 10
Set fso = CreateObject("Scripting.FileSystemObject")
txt = Split(fso.OpenTextFile(filename).ReadAll, vbNewLine)
Set f = fso.OpenTextFile(filename, 2)
For i = 0 To UBound(txt) - numLinesToRemove
f.WriteLine txt(i)
Next
f.Close
This approach only works for small files, though. If you need to process large files you usually can't read the entire file into memory. If you did your computer would start swapping data from memory to disk, causing the system to slow down to a crawl. To avoid this you normally read the file line by line in a loop and write to a temporary file, then replace the original file with the temp file after processing is complete.
Removing lines from the beginning of a file is still fairly trivial, because TextStream objects have a Line property that holds the current line number (i.e. the number of the line that the next ReadLine call would read).
Set f = fso.OpenTextFile(filename)
Set tmp = fso.OpenTextFile(filename & ".tmp", 2, True)
Do Until f.AtEndOfStream
If f.Line <= numLinesToRemove Then
f.SkipLine
Else
tmp.WriteLine f.ReadLine
End If
Loop
f.Close
tmp.Close
However, you can't do that for removing lines from the end of the file, because you don't know the number of lines beforhand. One way to deal with this is to create a ring buffer the size of the number of lines you want to remove, fill it as you read lines from the input file, and write lines to the output file when they are removed from the buffer. That way the last numLinesToRemove lines are still in the buffer (not written to the output file) when the loop terminates.
ReDim buf(numLinesToRemove) 'ring buffer
i = -1 'ring buffer pointer
Set f = fso.OpenTextFile(filename)
Set tmp = fso.OpenTextFile(filename & ".tmp", 2, True)
Do Until f.AtEndOfStream
i = (i + 1) Mod numLinesToRemove 'advance ring buffer pointer
'if current buffer slot is filled write it to the output file ...
If Not IsEmpty(buf(i)) Then tmp.WriteLine buf(i)
'... then put current line from input file into current buffer slot
buf(i) = f.ReadLine
Next
f.Close
tmp.Close
In both cases you'd replace the original file after processing is complete, e.g. like this:
fso.DeleteFile filename
fso.MoveFile filename & ".tmp", filename

just loop backwards in your for statement
For i=UBound(arrLines) To (UBound(arrLines) -10) step -1
Next

Related

VBScript not Reading Next Line

I have pieced together a script that is working, but not 100%.
I am reading values from a file (A) and then searching in a specific position in another file (B) for a match, then writing the entire row of data to a new file (C).
The script below works great on reading the first row in the data (file A), but it won't get past the first row.
Here is a sample list of strings I am searching for from file (A).
9899008KT2018012600000444
9899008KT2018012600000445
Here is my script:
Set fso = CreateObject("Scripting.FileSystemObject")
Set inFile = fso.OpenTextFile("C:\JeffTestFolder\9899008KT2018012600.txt", 1)
Set outFile = fso.OpenTextFile("C:\TestFolder\9899008KT2018012600_Compiled.txt", 8, True)
Set listFile = fso.OpenTextFile("C:\TestFolder\ListOfIDs.txt", 1)
Do Until listFile.AtEndOfStream
fName = listFile.ReadLine
Do Until inFile.AtEndOfStream
line = inFile.ReadLine
If Mid(line, 7, 25) = fName Then outFile.WriteLine line
Loop
Loop
I am stuck on how to get it to Loop and read the next line in file (A) then go search for that value in file (B) and write it to the new file (C).
If you want to compare each line of A against each line of B you need to repeat reading B for each line of A:
Do Until listFile.AtEndOfStream
fName = listFile.ReadLine
Set inFile = fso.OpenTextFile("C:\JeffTestFolder\9899008KT2018012600.txt")
Do Until inFile.AtEndOfStream
line = inFile.ReadLine
If Mid(line, 7, 25) = fName Then outFile.WriteLine line
Loop
inFile.Close
Loop
or read the entire file into an array or dictionary and use that array/dictionary as the reference:
txt = fso.OpenTextFile("C:\JeffTestFolder\9899008KT2018012600.txt").ReadAll
arr = Split(txt, vbNewLine)
Do Until listFile.AtEndOfStream
fName = listFile.ReadLine
For Each line In arr
If Mid(line, 7, 25) = fName Then outFile.WriteLine line
Next
Loop
Set dict = CreateObject("Scripting.Dictionary")
txt = fso.OpenTextFile("C:\JeffTestFolder\9899008KT2018012600.txt").ReadAll
For Each line In Split(txt, vbNewLine)
dict(Mid(line, 7, 25)) = True
Next
Do Until listFile.AtEndOfStream
fName = listFile.ReadLine
If dict.Exists(fName) Then outFile.WriteLine line
Loop
Which one to pick depends on file size and system resources. The second and third approach provide better performance, because they avoid repeated disk I/O, but may lead to memory exhaustion when the file is large.

Add certain text at end of certain lines in VBS

I have a .txt file which I wish to edit in VBS. The data is like the following:
Time, Column 1, Column 2
23/08/2017 8:30:00 AM, Data, Data
23/08/2017 8:35:00 AM, Data, Data
23/08/2017 8:40:00 AM, Data, Data
23/08/2017 8:45:00 AM, Data, Data
What I want is another 'column' called batch added at the end of the first line and then, the first value of time (23/08/2017 8:30:00 AM) to make up the data for this column so that the end result is something like the following:
Time, Column 1, Column 2, Batch
23/08/2017 8:30:00 AM, Data, Data, 23/08/2017 8:30:00 AM
23/08/2017 8:35:00 AM, Data, Data, 23/08/2017 8:30:00 AM
23/08/2017 8:40:00 AM, Data, Data, 23/08/2017 8:30:00 AM
23/08/2017 8:45:00 AM, Data, Data, 23/08/2017 8:30:00 AM
Note a comma separator exists between each column.
You can do something like this:
Start reading the data from the File line by line and store it in a temporary variable along with the data you want to append at the end of each line.
For the first line, data to be appended is ", Batch" and for the remaining lines data to be appended is the "Time Value" from the 2nd Line.
Open the file in write mode and write the data stored in that temporary variable
Code:
strPath = "C:\Users\gr.singh\Desktop\Desktop\Gurman\2017\as.txt" 'Replace this path with your file path
Set fso = CreateObject("scripting.filesystemobject")
Set rfile = fso.OpenTextFile(strPath,1) 'File opened in Read-only mode
While Not rfile.AtEndOfStream
temp=rfile.ReadLine()
If rfile.Line=2 Then 'The first line has been read by using the readline method due to which rfile.line gets set to 2. Hence, I have used 2 here for the 1st line. Similarly, I have used 3 fro the 2nd line in the ElseIf Condition
dataToAppend = "Batch"
ElseIf rfile.Line=3 Then
dataToAppend = Split(temp,",")(0)
End If
fulldata = fulldata & temp&", "&dataToAppend&"||"
Wend
rfile.Close
fulldata = Left(fulldata,Len(fulldata)-2)
Set wfile = fso.OpenTextFile(strPath,2) 'File opened in write mode
tempArr = Split(fulldata,"||")
For i=0 To UBound(tempArr)
wfile.WriteLine tempArr(i)
Next
wfile.Close
Set fso= Nothing
OUTPUT:
If your file is reasonably small you can read it as a whole and process it like this:
filename = "C:\path\to\your.txt"
Set fso = CreateObject("Scripting.FileSystemObject")
txt = fso.OpenTextFile(filename).ReadAll
data = Split(txt, vbNewLine)
If UBound(data) >= 0 Then data(0) = data(0) & ",batch"
If UBound(data) >= 1 Then
batchval = Left(data(1), InStr(data(1), ",")-1)
data(1) = data(1) & "," & batchval
End If
For i = 2 To UBound(data)
data(i) = data(i) & "," & batchval
Next
fso.OpenTextFile(filename, 2).Write Join(data, vbNewLine)
For large files this approach is not recommended, though, because it may lead to memory exhaustion, causing your computer to come grinding to a halt. If your file is large you're better off processing the file line by line, writing the output to a temporary file, and replacing the original once you're finished.
filename = "C:\path\to\your.txt"
tmpfilename = filename & ".tmp"
Set fso = CreateObject("Scripting.FileSystemObject")
inFile = fso.OpenTextFile(filename)
outFile = fso.OpenTextFile(tmpfilename, 2, True)
If Not inFile.AtEndOfStream Then outFile.WriteLine inFile.ReadLine & ",batch"
If Not inFile.AtEndOfStream Then
line = inFile.ReadLine
batchval = Left(line, InStr(line, ",")-1)
outFile.WriteLine line & "," & batchval
End If
Do Until inFile.AtEndOfStream
outFile.WriteLine inFile.ReadLine & "," & batchval
Loop
inFile.Close
outFile.Close
fso.DeleteFile filename, True
fso.MoveFile tmpfilename, filename

How to read every 20 lines from a text file using vbscript?

I have 180 lines in a text file and want to read every 20 lines (1-20, 21-40...)
Here is my current code:
Const ForReading = 1
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTextFile = objFSO.OpenTextFile("C:\Bess_Automation\EditFiles\TSTVLD1.txt", ForReading)
'Reading the count of lines
objTextFile.ReadAll
strLinecount=objTextFile.Line
msgbox strLinecount
strnumoftimes=Round((strLinecount/20),0)
msgbox strnumoftimes
Here's how I'd approach the problem. This code sets the number of lines to be read at a time initially then opens the file for reading and sets up an array. While we're not finished reading the file, we add a line from it to myArray.
When we hit a multiple of 20 lines read, we report that and do whatever we need to with those 20 lines (in my case, I've just echoed them to the screen, separated by semicolons).
Then we reset the array to be empty again and repeat until all the file has been read, then output the final batch of lines (as otherwise they'd be ignored since we only do anything with batches of 20 in the example).
Option Explicit
Const LINES_TO_READ = 20
Dim iLines, iTotalLines
Dim oFso : Set oFso = CreateObject("Scripting.FileSystemObject")
Dim oFile : Set oFile = oFso.OpenTextFile("C:\temp\mytextfile.txt", 1)
Dim myArray()
ReDim myArray(0)
iLines = 0
iTotalLines = 0
While Not oFile.AtEndOfStream
myArray(UBound(myArray)) = oFile.ReadLine
iLines = iLines + 1
ReDim Preserve myArray(UBound(myArray)+1)
If iLines Mod LINES_TO_READ = 0 Then
WScript.Echo iLines & " read now."
' do anything you like with the elements of myArray here before we reset it to empty
WScript.Echo Join(myArray, ";")
' reset array to be totally empty again
ReDim myArray(0)
End If
Wend
WScript.Echo "Final Lines: " & Join(myArray, ";")
WScript.Echo "Total lines in file: " & iLines

Delete Files After Filename - vbscript

Basically I am trying to write a script to delete files after a certain filename, so based on the below file list
FILE_000001_FULL.ZIP
FILE_000002_FULL.ZIP
FILE_000003_FULL.ZIP
FILE_000004_FULL.ZIP
FILE_000005_FULL.ZIP
FILE_000006_DELTA.ZIP
FILE_000007_DELTA.ZIP
FILE_000008_FULL.ZIP
Everything up until FILE_000005_FULL.ZIP would be deleted. The files are created using a tool and will be sorted by file name, so highest number first. Basically need the 2 latest FULL files kept and the DELTA's (if any) between them. I hope that makes sense.
So far, this is what I have, but just loops constantly, not just until it finds the 2 latest fulls.
Dim fso, folder, files, ToDel, sfolder
Set fso = CreateObject("Scripting.FileSystemObject")
sFolder = ("C:\MDS")
Set ToDel = fso.CreateTextFile ("C:\MDS\FileList.txt", True)
Set folder = fso.GetFolder(sFolder)
set files = folder.files
For each folderIDX In files
ToDel.WriteLine(folderidx.Name)
Next
ToDel.close
Dim arrFileLines()
i = 0
Set ObjFile = FSO.OpenTextFile("C:\MDS\FileList.txt", 1)
Do Until objFile.AtEndOfStream
Redim Preserve arrFileLines(i)
arrFileLines(i) = objFile.ReadLine
i = i + 1
Loop
ObjFile.Close
s = 0
Do While s < 2
For l = Ubound(arrFileLines) to LBound(arrFileLines) Step -1
For Each strLine in arrFileLines
IF InStr(strLine, "FULL") <> 0 Then
wscript.echo "Found Full!!!!"
wscript.echo strLine, s
s = S + 1
End If
Next
Next
LooP
My thoughts was to delete the lines from the text file, then use this text file to delete the files from the directory.
Hopefully that all makes sense and someone can pass some advice on!
You should be able to do this with two iterations through your folder and without the need/use of a text file. During the first pass, record the numbers assigned to the two latest FULL's. Then, in your second pass, delete any files that are less than your second-highest FULL.
Here's how it might look:
' First pass: Find the two latest FULLs...
For Each File In FSO.GetFolder("c:\mds").Files
' Is this a FULL?
If Right(File.Name, 8) = "FULL.ZIP" Then
' Get the numeric value from the file name (6 digits starting as pos 6)...
intNum = CLng(Mid(File.Name, 6, 6))
' Maintain the two latest FULLs...
If intNum > intMax1 Then
intMax2 = intMax1
intMax1 = intNum
ElseIf intNum > intMax2 Then
intMax2 = intNum
End If
End If
Next
' Second pass: Delete anything prior to the second-latest FULL...
For Each File In FSO.GetFolder("c:\mds").Files
intNum = CLng(Mid(File.Name, 6, 6))
If intNum < intMax2 Then File.Delete
Next

Read files in subfolders

I'm trying to make a script that we can output a specific string ino a files from a list of files in different subfolders.
My script works but onl for one directory. I need some help to make it works with subfolders
Const ForReading = 1
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set folder = objFSO.GetFolder("D:\vbs\logs\") ' here i have loads of subfolders with *.txt
Set outfile = objFSO.CreateTextFile("D:\vbs\ok\test.txt") ' my output file
for each file in folder.Files
Set testfile = objFSO.OpenTextFile(file.path, ForReading)
Do While Not testfile.AtEndOfStream
If instr (testfile.readline, "central") then ' i output every lines where there is the word "central"
outfile.writeline testfile.readline
End If
if instr (testfile.readline, "version") then ' i use this to parse my output file to get a indication between every files read
num = testfile.readline
mag = Split(num)
elseif testfile.AtEndOfStream = true then
outfile.writeline "Shop " & mag(4)
end if
Loop
testfile.close
next
outfile.close
See this answer to a similar question for a folder recursion example.
One remark about your existing code, though: each call of the ReadLine method reads the next line from the file, so something like this:
If instr (testfile.readline, "central") then
outfile.writeline testfile.readline
End If
will not output the line containing the word "central" (as your comments say), but the line after that line.
If you want to output the line containing the word you're checking for, you have to store the read line in a variable and continue with that variable:
line = testfile.ReadLine
If InStr(line, "central") Then
outfile.WriteLine line
End If
I would encapsulate your entire For...Each block into a new subroutine and then add a new For...Each block to capture all subFolders in the parent folder. I added that functionality to your script, see below.
Const ForReading = 1
Const Start_Folder = "D:\vbs\logs\" ' here i have loads of subfolders with *.txt
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set outfile = objFSO.CreateTextFile("D:\vbs\ok\test.txt") ' my output file
'Call the Search subroutine to start the recursive search.
Search objFSO.GetFolder(Start_Folder)
'Close the outfile after all folders have been searched
outfile.Close
Sub Search(sDir)
for each file in sDir.Files
Set testfile = objFSO.OpenTextFile(file.path, ForReading)
Do While Not testfile.AtEndOfStream
If instr (testfile.readline, "central") then ' i output every lines where there is the word "central"
outfile.writeline testfile.readline
End If
if instr (testfile.readline, "version") then ' i use this to parse my output file to get a indication between every files read
num = testfile.readline
mag = Split(num)
elseif testfile.AtEndOfStream = true then
outfile.writeline "Shop " & mag(4)
end if
Loop
testfile.close
next
'Find EACH SUBFOLDER.
For Each subFolder In sDir.SubFolders
'Call the Search subroutine to start the recursive search on EACH SUBFOLDER.
Search objFSO.GetFolder(subFolder.Path)
Next
End Sub

Resources