I have a file that looks like this:
Alpha,25,SomeBrand,Info
Gamma,2039,Crisps,Foobar
Epic,240,Win,Post
And I want to clear a certain line in this file, say line 2, so that it looks like this:
Alpha,25,SomeBrand,Info
Epic,240,Win,Post
How can I efficiently do this? This file has over 18000 lines, and I've tried reading in the complete file and writing back, but it was way too slow.
I don't know what is your file size but i've written a script (asp) is executed within 2.5 seconds.
Text file size is 35 million bytes and it has 35,000 lines.
Here:
<%#Language = VBScript %>
<%
Option Explicit
Dim oFso, oFile, arrLns, arrLNums, strOut, e
arrLNums = Array(15) '15th [and nnth] line(s) will be cleared
Set oFso = CreateObject("Scripting.FileSystemObject")
Set oFile = oFso.OpenTextFile("C:\old.txt", 1)
strOut = Replace(oFile.ReadAll(), vbCr, "")
arrLns = Split(strOut, vbLf)
For Each e In arrLNums : arrLns(e - 1) = "" : Next
strOut = Join(arrLns, vbCrLf)
oFso.CreateTextFile("C:\cleared.txt", True)_
.Write(strOut) 'Saved
oFile.Close
Set oFile = Nothing
Set oFso = Nothing
%>
As you can't use file pointer moving tricks to change the file 'on disk' in VBScript, you'll have to re-write it. Did you test whether using .ReadAll() and .Write is 'fast enough' for you? If yes, we could discuss a way to do the modifying efficiently. First question: Do you want to delete the offending line, or should it be replaced with an empty one?
Next Step:
This VBScript code:
Dim goFS : Set goFS = CreateObject( "Scripting.FileSystemObject" )
Dim sDir : sDir = "..\testdata\editlargefile"
Dim sSrcFSpec : sSrcFSpec = goFS.BuildPath( sDir, "lines.txt" )
Dim nLine : nLine = 5
Dim nSize : nSize = goFS.GetFile( sSrcFSpec ).Size
WScript.Echo nSize, "bytes in", sSrcFSpec
ReDim aHead( nLine - 2 )
Dim oTS, nIdx, sTail
Set oTS = goFS.OpenTextFile( sSrcFSpec )
For nidx = 0 To UBound( aHead )
aHead( nIdx ) = oTS.ReadLine()
Next
oTS.ReadLine
sTail = oTS.ReadAll()
oTS.Close
WScript.Echo Left( Join( aHead, vbCrLf ) & vbCrLf & vbCrLf & Left( sTail, 100 ), 150 )
Set oTS = goFS.CreateTextFile( sSrcFSpec, True )
oTS.Write Join( aHead, vbCrLf )
oTS.Write vbCrLf & vbCrLf
oTS.Write sTail
oTS.Close
output:
20888896 bytes in ..\testdata\editlargefile\lines.txt
This is line 1
This is line 2
This is line 3
This is line 4
This is line 6
This is line 7
This is line 8
This is line 9
This is line 10
Thi
=====================================================
xplfs.vbs: Erfolgreich beendet. (0) [11.42188 secs]
demonstrates the fastest VBScript way I can think of. The pseudo code
for a language able to do file pointer tricks would be
Open the file in read+write mode
Loop over the head lines to keep
If Delete
Skip line to delete
Reset write file pointer to end of previous line
Block write to file pointer till end
Else
Fill line to delete with spaces
End
Close the file
What language do you plan to use?
Related
We have some set of (powerpoint) pptx files which are targeted for different audiences
I was thinking of merging different slide sets based on target audiance
I want to know if it's possible to
Merge multiple powerpoint files into one
If a single file is changed, i want the same change to reflect into the merged file
Is this possible graphically or by a VBA?
Ex:
A.pptx
B.pptx
C.pptx
D.pptx
E.pptx
Set 1 (Dev.pptx):
A.pptx
B.pptx
D.pptx
Set 2 (Manager.pptx)
A.pptx
D.pptx
E.pptx
Set 3 (all.pptx)
A.pptx
B.pptx
C.pptx
D.pptx
E.pptx
If i change any one of the Pptx (A,b,c,d,e) the combined files should be updated automatically
The simplest and probably most reliable solution would be to put all of the slides into one file and then create custom shows, one for each target audience.
Another approach would be to have a main "menu" presentation, one slide with links to sub-presentations, one per audience. Each of those presentations would have its own "menu" slide that links to A.pptx, B.pptx etc. as needed.
At the end of A.pptx, add an End Presentation link; click on that (or just press ESC to quit the presentation) and you'll be returned to the sub-menu presentation.
This is possible with VBS on a Windows with installed PowerPoint.exe.
Create a script named merge.vbs with this content:
Option Explicit
Sub WriteLine ( strLine )
WScript.Stdout.WriteLine strLine
End Sub
Sub WriteError ( strLine )
WScript.Stderr.WriteLine strLine
End Sub
Dim inputFile1
Dim inputFile2
Dim outputFile
Dim objPPT
Dim objFso
Dim objPresentation
If WScript.Arguments.Count <> 3 Then
WriteError "You need to specify 2 input files and one output file."
WScript.Quit 1
End If
inputFile1 = WScript.Arguments(0)
inputFile2 = WScript.Arguments(1)
outputFile = WScript.Arguments(2)
Set objFso = CreateObject("Scripting.FileSystemObject")
If Not objFso.FileExists( inputFile1 ) Then
WriteError "Unable to find your input file " & inputFile1
WScript.Quit 1
End If
If Not objFso.FileExists( inputFile2 ) Then
WriteError "Unable to find your input file " & inputFile2
WScript.Quit 1
End If
WriteLine "Input File 1 : " & inputFile1
WriteLine "Input File 2 : " & inputFile2
WriteLine "Output File: " & outputFile
Set objPPT = CreateObject( "PowerPoint.Application" )
' Open presentation with window hidden
Set objPresentation = objPPT.Presentations.Open(inputFile1, True, False, False)
mergeAndKeepSourceFormatting objPresentation, inputFile2
' Reference for this at https://learn.microsoft.com/en-us/office/vba/api/powerpoint.presentation.saveas
WriteLine "Saving File: " & outputFile
objPresentation.SaveAs outputFile
objPresentation.Close
ObjPPT.Quit
'
' Add the file to the loaded presentation
'
Sub mergeAndKeepSourceFormatting(ByRef objPresentation, ByVal newPptxFile)
WriteLine "Merging file: " & newPptxFile
Dim newSlides
Dim oldSlides
oldSlides = objPresentation.Slides.Count
newSlides = objPresentation.Slides.InsertFromFile( newPptxFile, objPresentation.Slides.Count)
objPresentation.Slides.Range(FillRangeArray(oldSlides + 1, oldSlides + newSlides)).ApplyTemplate newPptxFile
End Sub
Function FillRangeArray(n1, n2)
Dim myArr()
Redim myArr(n2 - n1)
Dim i
For i = 0 to (n2 - n1)
myArr(i) = n1 + i
Next
FillRangeArray = myArr
End Function
Then from the command line you can call it:
CSCRIPT merge.vbs "A.pptx" "B.pptx" "resultA_B.pptx"
Please adjust the script to your needs or call it several times to merge the resulting file with the next one.
How do I edit a record in a CSV file?
for example I have a .csv file named "test.csv" and inside it is:
"123","Active"
"456","Not-Active"
"999000123","Active"
How can I edit "456" and change it from Not-Active to Active
The only way I can think of it is to:
Open the .csv file. Maybe store the data inside a string?
Search for "456",".
Get the line position of "456",". How to do this?
Delete the line that we just got the position of. How to do this?
Recreate the line with what we want. How to do this?
Insert the recreated data in the line position. How to do this?
Save the .csv file.
But is there not a easier way to do this?
And if not how do I do steps # 4, 5, and 6?
Maybe to convert it onto an Array or something? But I have no idea how to do this in Classic ASP.
Based on Ekkehards answer, here is the ASP version. The .csv file needs to be located in the same directory as the .asp script. Feel free to award the points to Ekkehard
<%#LANGUAGE="VBSCRIPT"%>
<% option explicit %>
<%
Dim goFS : Set goFS = CreateObject("Scripting.FileSystemObject")
Dim tsIn : Set tsIn = goFS.OpenTextFile(Server.MapPath( "46734115.csv"))
Dim tsOut : Set tsOut = goFS.CreateTextFile(Server.MapPath("46734115-2.csv"))
Dim sLine
Do Until tsIn.AtEndOfStream
sLine = tsIn.ReadLine()
dim pos : pos = instr( sLine, """456"",")
Response.Write(pos)
if pos > 0 then
' to keep things simple, just replace the whole line
sLine = """456"",""Active"""
end if
tsOut.WriteLine sLine
' Just so there is something to see: print line to the browser window
Response.Write( sLine & "<br />")
Loop
tsOut.Close
tsIn.Close
%>
A simplyfied version of the script #abr mentioned:
Dim goFS : Set goFS = CreateObject("Scripting.FileSystemObject")
Dim tsIn : Set tsIn = goFS.OpenTextFile("..\data\46734115.csv")
Dim tsOut : Set tsOut = goFS.CreateTextFile("..\data\46734115-2.csv")
Dim sLine
Do Until tsIn.AtEndOfStream
sLine = tsIn.ReadLine()
WScript.Echo "<", sLine
If "456," = Left(sLine, 4) Then
sLine = "789,""something else"""
End If
WScript.Echo ">", sLine
tsOut.WriteLine sLine
WScript.Echo
Loop
tsOut.Close
tsIn.Close
output:
type ..\data\46734115.csv
123,"Active"
456,"Not-Active"
999000123,"Active"
cscript 46734115-3.vbs
< 123,"Active"
> 123,"Active"
< 456,"Not-Active"
> 789,"something else"
< 999000123,"Active"
> 999000123,"Active"
type ..\data\46734115-2.csv
123,"Active"
789,"something else"
999000123,"Active"
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
I have text files that are approximately 6MB in size. There are some lines that contain the NULL (Chr(0))character that I would like to remove.
I have two methods to do this: using Asc()=0 but this takes approximately 50s to complete, the other method uses InStr (line, Chr(0)) =0 (fast ~ 4sec)but the results remove vital info from the lines which contain the NULL characters.
First line of text file as example:
##MMCIBN.000NULL7NULL076059NULL7653NULL1375686349NULL2528NULL780608NULL10700NULL\NULL_NC_ACT.DIR\CFG_RESET.INI
First method (works but VERY slow)
function normalise (textFile )
Set fso = CreateObject("Scripting.FileSystemObject")
writeTo = fso.BuildPath(tempFolder, saveTo & ("\Output.arc"))
Set objOutFile = fso.CreateTextFile(writeTo)
Set objFile = fso.OpenTextFile(textFile,1)
Do Until objFile.AtEndOfStream
strCharacters = objFile.Read(1)
If Asc(strCharacters) = 0 Then
objOutFile.Write ""
nul = true
Else
if nul = true then
objOutFile.Write(VbLf & strCharacters)
else
objOutFile.Write(strCharacters)
end if
nul = false
End If
Loop
objOutFile.close
end function
The output looks like this:
##MMCIBN.000
7
076059
7653
1375686349
2528
780608
10700
\
_NC_ACT.DIR\CFG_RESET.INI
Second method code:
filename = WScript.Arguments(0)
Set fso = CreateObject("Scripting.FileSystemObject")
sDate = Year(Now()) & Right("0" & Month(now()), 2) & Right("00" & Day(Now()), 2)
file = fso.BuildPath(fso.GetFile(filename).ParentFolder.Path, saveTo & "Output " & sDate & ".arc")
Set objOutFile = fso.CreateTextFile(file)
Set f = fso.OpenTextFile(filename)
Do Until f.AtEndOfStream
line = f.ReadLine
If (InStr(line, Chr(0)) > 0) Then
line = Left(line, InStr(line, Chr(0)) - 1) & Right(line, InStr(line, Chr(0)) + 1)
end if
objOutFile.WriteLine line
Loop
f.Close
but then the output is:
##MMCIBN.000\CFG_RESET.INI
Can someone please guide me how to remove the NULLS quickly without losing information. I have thought to try and use the second method to scan for which line numbers need updating and then feed this to the first method to try and speed things up, but quite honestly I have no idea where to even start doing this!
Thanks in advance...
It looks like the first method is just replacing each NULL with a newline. If that's all you need, you can just do this:
Updated:
OK, sounds like you need to replace each set of NULLs with a newline. Let's try this instead:
strText = fso.OpenTextFile(textFile, 1).ReadAll()
With New RegExp
.Pattern = "\x00+"
.Global = True
strText = .Replace(strText, vbCrLf)
End With
objOutFile.Write strText
Update 2:
I think the Read/ReadAll methods of the TextStream class are having trouble dealing with the mix of text and binary data. Let's use an ADO Stream object to read the data instead.
' Read the "text" file using a Stream object...
Const adTypeText = 2
With CreateObject("ADODB.Stream")
.Type = adTypeText
.Open
.LoadFromFile textFile
.Charset = "us-ascii"
strText = .ReadText()
End With
' Now do our regex replacement...
With New RegExp
.Pattern = "\x00+"
.Global = True
strText = .Replace(strText, vbCrLf)
End With
' Now write using a standard TextStream...
With fso.CreateTextFile(file)
.Write strText
.Close
End With
I tried this method (update2) for reading a MS-Access lock file (Null characters terminated strings in 64 byte records) and the ADODB.Stream didn't want to open an already in use file. So I changed that part to :
Set fso = CreateObject("Scripting.FileSystemObject")
Set f = fso.GetFile(Lfile)
z = f.Size
set ts = f.OpenAsTextStream(ForReading, 0) 'TristateFalse
strLog = ts.Read(z)
ts.Close
set f = nothing
' replace 00 with spaces
With New RegExp
.Pattern = "\x00+"
.Global = True
strLog = .Replace(strLog, " ")
End With
' read MS-Access computername and username
for r = 1 to len(strLog) step 64
fnd = trim(mid(strLog,r, 32)) & ", " & trim(mid(strLog,r+32, 32)) & vbCrLf
strRpt = strRpt & fnd
next
how to read text file word by word in VB script? please give all possible functions.
This:
Dim sAll : sAll = readAllFromFile("..\data\wbw.txt")
WScript.Echo sAll
WScript.Echo "-----------------------"
Dim oRE : Set oRE = New RegExp
oRE.Global = True
oRE.Pattern = "\w+"
Dim oMTS : Set oMTS = oRE.Execute(sAll)
Dim oMT
For Each oMT In oMTS
WScript.Echo oMT.Value
Next
Output:
===============================================================================
How to read text file word by word in VB script?
Please give all possible functions.
First, read the file line-by-line into an array. Then, when you're reading
through the array, parse each line word-by-word. As such:
-----------------------
How
to
read
text
file
word
by
word
in
VB
script
Please
give
all
possible
functions
First
read
the
file
line
by
line
into
an
array
Then
when
you
re
reading
through
the
array
parse
each
line
word
by
word
As
such
===============================================================================
avoids all the atrocities of Zomgie's solution:
Not usable with Option Explicit
Useless Dim of fixed array of no size
Useless array of lines
Costly ReDim Preserve with extra counter
Useless variable inputText
Split on " " makes "First," a word
First, read the file line-by-line into an array. Then, when you're reading through the array, parse each line word-by-word. As such:
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile("c:\file.txt", ForReading)
Const ForReading = 1
Dim arrFileLines()
i = 0
Do Until objFile.AtEndOfStream
Redim Preserve arrFileLines(i)
arrFileLines(i) = objFile.ReadLine
i = i + 1
Loop
objFile.Close
For Each strLine in arrFileLines
inputText = strLine
outputArray = Split(inputText)
For Each x in outputArray
WScript.Echo "Word: " & x
Next
Next