September 11th, 2006

How Can I Delete Just the Last Line of a Text File?

Hey, Scripting Guy! Question

Hey, Scripting Guy! How can I delete just the last line of a text file?

— AD

SpacerHey, Scripting Guy! AnswerScript Center

Hey, AD. You know, it’s been a long, hard day here at Microsoft, one of those days when everyone and everything seems to be against you. Many people, when faced with a day like today, turn to the so-called comfort foods: meatloaf, beef stew, mashed potatoes and gravy, any food that’s familiar and reliable. When you’re a Scripting Guy faced with a day like today, you turn to the so-called comfort scripts: reading from and writing to text files. Familiar and reliable.

Note. Admittedly, we Scripting Guys would prefer to turn to comfort foods ourselves. However, we’re stuck with comfort scripts, at least until they start putting mashed potatoes and gravy into the vending machines around here.

It’s nowhere near as good as a meatloaf sandwich, but here’s a script that deletes just the last line of a text file:

Const ForReading = 1
Const ForWriting = 2

Set objFSo = CreateObject(“Scripting.FileSystemObject”) Set objFile = objFSO.OpenTextFile(“c:\scripts\test.txt”, ForReading)

strContents = objFile.ReadAll objFile.Close

arrLines = Split(strContents, vbCrLf)

Set objFile = objFSO.OpenTextFile(“c:\scripts\test.txt”, ForWriting)

For i = 0 to UBound(arrLines) – 1 objFile.WriteLine arrLines(i) Next

objFile.Close

Actually, no, we hadn’t planned on explaining how the script works; when you order a meatloaf sandwich no one ever explains how that’s made, do they?

Oh, fine; we’ll see what we can do. We start out by defining a pair of constants, ForReading and ForWriting; we’ll use these constants to specify read-only or write-only mode when opening the text file. As usual, we need to open this file twice. In just a second we’re going to open the file for reading, and read in the existing contents. We’ll close the file, modify the contents in memory, then reopen the file and save the modified contents (that is, the old contents minus the very last line). It’s a bit of a hassle, but we have little choice here: the FileSystemObject won’t let us open a file for both reading and writing. Instead, at any given time we’re limited to doing one of those operations or the other.

And, yes, that is a bit like eating the mashed potatoes, and only then being able to eat the gravy, isn’t it?

After defining the two constants we create an instance of the Scripting.FileSystemObject and use the OpenTextFile method to open the file C:\Scripts\Testtxt. With the file open for reading we then use this line of code to read the entire text file and store the contents in a variable named strContents:

strContents = objFile.ReadAll

With the entire file stashed safely away in memory we then call the Close method to (temporarily) close the file.

Now what? As it turns out, our next step is to use the Split function to split the contents of the file into an array name arrLines, with each item in the array representing a line in the text file. We do that by splitting on the carriage return-linefeed character (or, as VBScript knows this character, vbCrLf):

arrLines = Split(strContents, vbCrLf)

Why do we do that? Well, the FileSystemObject doesn’t really know much about text files; for example, it doesn’t know which line is the last line in a given file. In that respect, arrays are a little smarter than the FileSystemObject. After all, any array can tell what its last item is: you can determine the last item in an array simply by calling the Ubound function, which returns the index number (subscript) of that item. For example, if the Ubound function returns a 13, then the last item in the array must have an index number of 13; in turn, that would mean thet we’re dealing with arrLines(13).

Hold on; we’re getting to that. So why is it useful to know that which item is the last item in the array? Well, we don’t want the last item to be included in our revised text file. If we know that the last item is item 13, then we know that our revised text file should only include items 0 through 12 (remember, the first item in an array is always item 0). We want to grab items 0 through 12 and then stop; that effectively deletes the last line in the text file.

Good idea: maybe we should just show you what we mean. After creating the array we reopen the text file, this time for writing; as you know, information we write to the file will completely replace the existing contents of the file. We then set up a For Next loop that runs from 0 to the Ubound value of the array minus 1:

For i = 0 to UBound(arrLines) – 1

Boy, you have a lot of questions today, don’t you? Why Ubound minus 1? Well, the Ubound function identifies the last item in the array. As we know, we don’t want the last item; however, we do want all the items up to – but not including – the last item. If the last item in the array is item 13, taking the Ubound value (13) and subtracting 1 leaves us with 12, which turns out to be the very value we need in our For Next loop. (To get items 0 through 12 our loop needs to run from 0 to, well, 12.) That’s why we use Ubound minus 1.

Inside our loop, and on the first go-round, we use the WriteLine method to write the value of array item 0 (the first item in the array, represented by the counter variable i) to the text file:

objFile.WriteLine arrLines(i)

We then loop around and repeat the process with the counter variable i equal to 1, meaning that we’ll write the value of array item 1 to the text file. This continues until we write the value of item 12 (the next-to-last item in the array) and then exit the loop. At that point we close the file and call it a day, without ever writing the last item in the array to the text file. We took a somewhat roundabout path here, but the net effect is that we’ve deleted the last line in the text file (simply by rewriting all the lines except the last line).

So will this really work? Of course it will. Suppose our text file looks like this, with the letter E being the actual last line of the file (that is, there’s no blank line following it):

A
B
C
D
E

What do you get back when you run the script? This:

A
B
C
D

Note. So what if your text file does have a blank line at the end? One thing you could do is check for that possibility – and remove the blank line – before you convert the text file to an array. Fortunately, we have a Hey, Scripting Guy! column that tells you how to do that very thing.

And that’s how the script works. As for the meatloaf sandwich, take two pieces of bread, put a little mustard on both pieces, and then slap a hunk of meatloaf in the middle. Feel free to use this recipe any time. Just make sure you credit the Scripting Guys.

Author

0 comments

Discussion are closed.