Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

vbs to line count a text file

Status
Not open for further replies.

sumgirl

IS-IT--Management
Mar 19, 2003
55
US
Can anyone tell me how (or point me to how) count the number of lines in a text file?
 
Hello davidnix,

One way to do it is use split the contents fully read, and check the ubound of the array so result.
Code:
const filename="abc_test.txt"  'make your input
set fso=createobject("scripting.filesystemobject")
set ofile=fso.opentextfile(filename)
strcontents=ofile.readall
ofile.close
set ofile=nothing
set fso=nothing
acontents=split(strcontents,vbcrlf)
wscript.echo "Number of line : " & cstr(ubound(acontents)+1)
The other obvious way is to read line by line once the file is opened while not AtEndOfStream. This require slight more lines of code but not necessarily inferior performance-wise.

regards - tsuji
 
you can do a

objTextStream.ReadAll and then
objTextStream.Line ....this will give you the end line

i think
 
tsuji,
Thanks...

That's good code!

How would you modify to write the 'count' results to another text file instead of sending message box to the screen?

Thanks, Ed
 
Hello flowinlikeacoolbreeze,

That a good handle!

I would do something like this.
Code:
const filename="abc_test.txt"  'make your input
const storage="def_storage.txt" 'make your input
const ForReading = 1, ForWriting = 2, ForAppending = 8
set fso=createobject("scripting.filesystemobject")
on error resume next
set ofile=fso.opentextfile(filename, ForReading)
if err.number<>0 then
	set ofile=nothing
	set fso=nothing
	wscript.echo &quot;Text file not found. Operation aborted.&quot;
	wscript.quit(1)
end if
on error goto 0
strcontents=ofile.readall
ofile.close
acontents=split(strcontents,vbcrlf)
on error resume next
set ofile=fso.opentextfile(storage, ForAppending)
if err.number<>0 then
	set ofile=fso.createtextfile(storage)
end if
on error goto 0
ofile.writeline &quot;(file, #lines) = (&quot; & filename & &quot;, &quot; & cstr(ubound(acontents)+1) & &quot;)&quot;
ofile.close
set ofile=nothing
set fso=nothing
regards - tsuji
 
Correction:

Should add a line clearing the error in the error handle. Add the red line:
Code:
if err.number<>0 then
    set ofile=fso.createtextfile(storage)
err.clear
Code:
end if
-tsuji
 
MRMovie's example looks very good, short and sweet, but I've always thought reading a file took longer than doing a skip. This example takes a bit more code to get the number of lines, but never actually reads the file contents:

' get the number of lines in the input file
' first, get the file size
set objFile = objFSO.getFile(Filename)
intFileSize = objFile.size

' next, open the file and skip to the end
set objInputTS = objFSo_OpentextFile(Filename, ForReading)
objInputTS.skip(intFileSize)

' and read the line number
intLines = objInputTS.line

This is just the guts without any error handling or cleanup.

Mark
 
The
Code:
Skip
method does read the file. That's how it works, it simply doesn't return those bytes to you.

Also:

objInputTS.skip(intFileSize)

Is incorrect, but viable syntax. Correct syntax looks like:

objInputTS.skip intFileSize

What you have there is somewhat like saying:

size = (intFileSize)

The parentheses are redundant, and will probably cause you to be frustrated when calling a Sub or a method with more than one parameter:

Sub XXX(a, b)
:
End Sub


XXX(12, 13) <-- syntax error!
XXX 12, 13 <-- correct syntax


One should also be aware that the &quot;read the whole file into memory as a glob and do a Split() on it&quot; will fail or hang on very large files (> 200MB) and results in a good degree of thrashing on medium sized files (50MB or so). The &quot;read each line and count it&quot; approach can be very slow however.

The more general way to handle this whole business involves reading the file in good-sized chunks (of say 32K to 64K) and counting the line delimiters in each chunk. It is a tradeoff between memory usage and script execution time.

For small files (under 1-2MB?) the methods shown above work well though.

Maybe somebody totally bored wants to benchmark the various options?
 
Hi,

I've just found this page as it's exactly what I need...Well, almost!

Is there a way of modifying the code to read in several files and also, create several output files?

I have a directory that will contain several files, but the filenames are uniquely created and I have no way of knowing what they will be called. What would be absolutely ideal, would be to read in the first file - let's call it &quot;file1.txt&quot;, count the number of lines and then in &quot;file1.txt&quot;, right at the top, add the number of lines and then write it out again...A little more explanation:

File1:

Line1
Line2
Line3
Line4
Line5
*EOF*

Script opens the file, counts the lines and then writes out to the same file:

5
Line1
Line2
Line3
Line4
Line5
*EOF*

Is this possible?

Many thanks to anyone who can help me!
 
Hello Phreeneazie,

It would then be:
Code:
const filename=&quot;abc_test.txt&quot;  'make your input
const ForReading = 1, ForWriting = 2, ForAppending = 8
set fso=createobject(&quot;scripting.filesystemobject&quot;)
on error resume next
set ofile=fso.opentextfile(filename, ForReading)
if err.number<>0 then
    set ofile=nothing
    set fso=nothing
    wscript.echo &quot;Text file not found. Operation aborted.&quot;
    wscript.quit(1)
end if
on error goto 0
strcontents=ofile.readall
ofile.close
acontents=split(strcontents,vbcrlf)
acontents(0)=cstr(ubound(acontents)+1) & vbcrlf & acontents(0)
set ofile=fso.createtextfile(filename, true)
for i=0 to ubound(acontents)
    ofile.writeline acontents(i)
next
ofile.close
set ofile=nothing
set fso=nothing
regards - tsuji
 
tsuji,

that works fantastically well! (Not that I ever doubted you!).

That is extremely helpful and I'll be using it a lot!

Many thanks...

I am <so> glad I've found you guys!
 
Hi again!

Just realised that the above code always opens the same file - &quot;abc_def.txt&quot;..How do I make it so that it will open any file it sees in a particular directory? I will have somewhere in the region of 100-200 files that I will need to run this script against and will have no way of knowing the name of the file...

Thanks!
 
Phreeneazie,

[1] The above script is written for dealing with a certain file with full path spec. It is a well-isolated task and the script deals with that task. Nothing hold you back from taking the const filename up there to be some inputs from other script lines.

[2] Remaining in the above script: It modifies the file by completely overwriting and rewriting it. In case that the file(s) is so critical that you do not want accidently lost during the rewriting process, create the new filename of some affinity to the original file. After completing the process, you can safely delete the original file (.deletefile method) and the rename the new filename to the original filename (.movefile method). This is a little detail you can bear in mind.

[3] Return to your new question. You can enumerate the files within a named path. So the structure of the script would be like this.
Code:
'const filename=&quot;abc_test.txt&quot;  'commented out
const sPath = &quot;d:\test&quot;   'some path you specify
const ForReading = 1, ForWriting = 2, ForAppending = 8
set fso=createobject(&quot;scripting.filesystemobject&quot;)
on error resume next
set ofolder=fso.getfolder(sPath)
if err.number<>0 then
    set ofolder=nothing
    set fso=nothing
    wscript.echo &quot;Path not found. Operation aborted.&quot;
    wscript.quit(1)
end if
on error goto 0
set colfiles=sfolder.files
for each opickedfile in colfiles
    filename=opickedfile.path
    'here return again to the relevant lines
    set ofile=fso.opentextfile(filename, ForReading)
    strcontents=ofile.readall
    ofile.close
    acontents=split(strcontents,vbcrlf)
    acontents(0)=cstr(ubound(acontents)+1) & vbcrlf & acontents(0)
    set ofile=fso.createtextfile(filename, true)
    for i=0 to ubound(acontents)
        ofile.writeline acontents(i)
    next
    ofile.close
    set ofile=nothing
next
set colfiles=nothing
set ofolder=nothing
set fso=nothing
[code]
[4] I have gone a fair distance in the detail just because if one is not familier with the working of the script, one may eaily be at lost. After these demonstration, you should be able to get the feel that it is all just clueing little tasks together. Nothing more. And you could adapte to the always varying requirements.

regards - tsuji
 
Thanks again for that, really making progress!

I just tried running that script and I received (my first!) error message:

Script: c:\linecount.vbs
Line: 13
Char: 1
Error: Object required: 'sfolder'
Code: 800A01A8
Source: Microsoft VBScript runtime error

?

Sorry for all the questions etc...And apologies for kinda taking over this thread!
 
Phreeneazie,

It is a typo, my bad. The line should be read:

set colfiles=ofolder.files

I draft the above on the edit textarea, so there might be more typos, cannot guranteed.

- tsuji
 
Yep, works brilliantly!

Thank-you very much for the help - I'll implement it today and it should all be plain-sailing from now!

Thanks again :)
 
Eek! One more thing...It's working great except for one thing - it's adding one number too many - for instance, if I have a 5 line file, it's putting a 6 at the top of the file. If it's a 1 line file, it's putting a 2 and so on..

I don't know if it's reading an extra CRLF or something in the data?

I've figured that somehow I need to do a '-1' somewhere in the script and altho I have tried it in various places, it doesn't seem to make any difference...

Thanks!
 
Phreeneazie,

This is some fine detail. If the last line was entered with a hard-enter, this could happen. And, this is the device taking care of this:
Code:
acontents=split(strcontents,vbcrlf)
'adding &quot;if-end if&quot; here
if IsEmpty(acontents(ubound(acontents))) then
    ReDim Preserve acontents(ubound(acontents)-1)
end if
acontents(0)=cstr(ubound(acontents)+1) & vbcrlf & acontents(0)
I have not physically checked it, post back if it fires a runtime error.

I use IsEmpty here. Consequently, if the last line containing only spaces will be taken as one acceptable line. Else, some kind of trim will do.

- tsuji
 
Thanks once again for the quick reply!

It still appears to be doing the same thing...Here's the script in full:

const sPath = &quot;c:\testarena&quot; 'some path you specify
const ForReading = 1, ForWriting = 2, ForAppending = 8
set fso=createobject(&quot;scripting.filesystemobject&quot;)
on error resume next
set ofolder=fso.getfolder(sPath)
if err.number<>0 then
set ofolder=nothing
set fso=nothing
wscript.echo &quot;Path not found. Operation aborted.&quot;
wscript.quit(1)
end if
on error goto 0
set colfiles=ofolder.files
for each opickedfile in colfiles
filename=opickedfile.path
'here return again to the relevant lines
set ofile=fso.opentextfile(filename, ForReading)
strcontents=ofile.readall
ofile.close
acontents=split(strcontents,vbcrlf)
'adding &quot;if-end if&quot; here
if IsEmpty(acontents(ubound(acontents))) then
ReDim Preserve acontents(ubound(acontents)-1)
end if
acontents(0)=cstr(ubound(acontents)+1) & vbcrlf & acontents(0)
set ofile=fso.createtextfile(filename, true)
for i=0 to ubound(acontents)
ofile.writeline acontents(i)
next
ofile.close
set ofile=nothing
next
set colfiles=nothing
set ofolder=nothing
set fso=nothing

No errors received, just doing the same thing. The file I tested it on, has five lines of data and then a hard crlf at the end - if I move the cursor from the top of the file to the bottom, it stops on line 6 -> 1 line after the last line of data.

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top