469,591 Members | 1,527 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,591 developers. It's quick & easy.

Scanner class and last line in a file

I've been having some trouble getting the Scanner class to operate the
way I'd like. I'm doing some fairly basic file IO and I can't seem to
get the class to load the last line/token any way I try.
First, I tried using the following:

File InFile=new File("input.txt");
Scanner In=new Scanner(InFile);

String Ln;
for ( Ln=In.nextLine() ; In.hasNextLine() ; Ln=In.nextLine() ) {
// Do stuff with Ln in here.
}

Unfortunately, this moves the "cursor" in the file down one line, and
returns the text skipped - probably not what I was trying to do. Also,
when it gets to the end of the file, hasNextLine() returns false (as
it should) and the loop finishes. Unfortunately, it's still left
precious information in the file!

When I tell it to load the final line using nextLine(), it tries
advancing past the end of the file and gives me a
NoSuchElementException.
So, I tried changing it up to be the following:

File InFile=new File("input.txt");
Scanner In=new Scanner(InFile).useDelimiter("\n");

String Ln;
for ( Ln=In.next() ; In.hasNext() ; Ln=In.next() ) {
// Do stuff with Ln in here.
}

This, however, according to the method description, only returns those
tokens which both start AND end with the delimiter - making it
impossible for me to use it to load the last token in the file, simply
because there's no newlines after it.
How can I get that last line (preferably, using the Scanner class)? Is
it possible to specify that the EOF sequence is a delimiter - or would
that even work?

Thanks in advance for any help,
DemonWasp

Sep 24 '06 #1
7 24464
Lew
DemonWasp wrote:
....
First, I tried using the following:

File InFile=new File("input.txt");
Scanner In=new Scanner(InFile);

String Ln;
for ( Ln=In.nextLine() ; In.hasNextLine() ; Ln=In.nextLine() ) {
// Do stuff with Ln in here.
}

Unfortunately, this moves the "cursor" in the file down one line, and
returns the text skipped - probably not what I was trying to do. Also,
when it gets to the end of the file, hasNextLine() returns false (as
it should) and the loop finishes. Unfortunately, it's still left
precious information in the file!

When I tell it to load the final line using nextLine(), it tries
advancing past the end of the file and gives me a
NoSuchElementException.
...
From the API docs
<http://java.sun.com/j2se/1.5.0/docs/api/java/util/Scanner.html>:

Scanner.hasNextLine()
"Returns true if there is another line in the input of this scanner. ... The
scanner does not advance past any input."

Scanner.nextLine()
"Advances this scanner past the current line and returns the input that was
skipped. This method returns the rest of the current line, excluding any line
separator at the end. The position is set to the beginning of the next line."

In other words, nextLine() is supposed to return the text that was skipped.

If your input has only one line (or zero), the loop will not execute. The
initialization will read the one line, then the condition will fail because
there is no second line.

When the loop finished and you tried to call nextLine() again (assuming you
used the same Scanner instance), it threw the exception because hasNextLine()
had already failed. Calling nextLine() when ! hasNextLine() raises the exception.

Try something like:

Scanner in = new Scanner( inFile );
while ( in.hasNextLine() )
{
String line = in.nextLine();
// do something with line
}

(The convention is to name variables with a lower-case first letter.)

- Lew
Sep 24 '06 #2
On Sun, 24 Sep 2006 17:25:34 -0400, Lew <co****@comcast.netwrote:

<snip>
>Scanner.hasNextLine()
"Returns true if there is another line in the input of this scanner. ... The
scanner does not advance past any input."

Scanner.nextLine()
"Advances this scanner past the current line and returns the input that was
skipped. This method returns the rest of the current line, excluding any line
separator at the end. The position is set to the beginning of the next line."

In other words, nextLine() is supposed to return the text that was skipped.
I recognise this, but I probably didn't make it sufficiently clear in
my post. However, this wasn't the main issue.
>If your input has only one line (or zero), the loop will not execute. The
initialization will read the one line, then the condition will fail because
there is no second line.

When the loop finished and you tried to call nextLine() again (assuming you
used the same Scanner instance), it threw the exception because hasNextLine()
had already failed. Calling nextLine() when ! hasNextLine() raises the exception.

Try something like:

Scanner in = new Scanner( inFile );
while ( in.hasNextLine() )
{
String line = in.nextLine();
// do something with line
}

(The convention is to name variables with a lower-case first letter.)
Yeah, but I'm unconventional :P. Again though, this example misses the
point of the question that I was asking.

What I *was* asking was "how do I get the last line from a file, even
when there is no trailing whitespace?"

Thanks anyway,
DemonWasp
Sep 25 '06 #3
DemonWasp wrote:
On Sun, 24 Sep 2006 17:25:34 -0400, Lew <co****@comcast.netwrote:

<snip>
>Scanner.hasNextLine()
"Returns true if there is another line in the input of this scanner. ... The
scanner does not advance past any input."

Scanner.nextLine()
"Advances this scanner past the current line and returns the input that was
skipped. This method returns the rest of the current line, excluding any line
separator at the end. The position is set to the beginning of the next line."

In other words, nextLine() is supposed to return the text that was skipped.

I recognise this, but I probably didn't make it sufficiently clear in
my post. However, this wasn't the main issue.
>If your input has only one line (or zero), the loop will not execute. The
initialization will read the one line, then the condition will fail because
there is no second line.

When the loop finished and you tried to call nextLine() again (assuming you
used the same Scanner instance), it threw the exception because hasNextLine()
had already failed. Calling nextLine() when ! hasNextLine() raises the exception.

Try something like:

Scanner in = new Scanner( inFile );
while ( in.hasNextLine() )
{
String line = in.nextLine();
// do something with line
}

(The convention is to name variables with a lower-case first letter.)

Yeah, but I'm unconventional :P. Again though, this example misses the
point of the question that I was asking.

What I *was* asking was "how do I get the last line from a file, even
when there is no trailing whitespace?"

Thanks anyway,
DemonWasp
I don't confuse being unconventional with being dense. He just showed
you what you need to do. Personally, I would point you to read the
Scanner api. Learn how to Google the groups also.

--
Thanks in Advance...
IchBin, Pocono Lake, Pa, USA http://weconsultants.phpnet.us
__________________________________________________ ________________________

'If there is one, Knowledge is the "Fountain of Youth"'
-William E. Taylor, Regular Guy (1952-)
Sep 25 '06 #4

"DemonWasp" <jd****@msn.comwrote in message
news:r5********************************@4ax.com...
I've been having some trouble getting the Scanner class to operate the
way I'd like. I'm doing some fairly basic file IO and I can't seem to
get the class to load the last line/token any way I try.
First, I tried using the following:

File InFile=new File("input.txt");
Scanner In=new Scanner(InFile);

String Ln;
for ( Ln=In.nextLine() ; In.hasNextLine() ; Ln=In.nextLine() ) {
// Do stuff with Ln in here.
}

Unfortunately, this moves the "cursor" in the file down one line, and
returns the text skipped - probably not what I was trying to do. Also,
when it gets to the end of the file, hasNextLine() returns false (as
it should) and the loop finishes. Unfortunately, it's still left
precious information in the file!

When I tell it to load the final line using nextLine(), it tries
advancing past the end of the file and gives me a
NoSuchElementException.
In your "Do stuff with Ln in here" section, doesn't it process the last
line right before exiting the loop?
>

So, I tried changing it up to be the following:

File InFile=new File("input.txt");
Scanner In=new Scanner(InFile).useDelimiter("\n");
Don't bother with "useDelimiter". I think that'll be a dead end for you.

- Oliver

Sep 25 '06 #5
DemonWasp <jd****@msn.comwrote:
>What I *was* asking was "how do I get the last line from a file, even
when there is no trailing whitespace?"
I can't repro the problem - help me understand what I'm missing. I'm using
the following test class:

import java.io.*;
import java.util.Scanner;
public class ScannerTest {
public static void main(String[] args) throws Exception {
if (args == null || args.length != 1) {
System.out.println("Specify filename.");
System.exit(1);
}

File input = new File(args[0]);
InputStream is = new FileInputStream(input);

int lineNum=0;
for (Scanner s = new Scanner(is); s.hasNextLine();) {
String line = s.nextLine();
System.out.println(lineNum++ + " " + line);
}
}
}

And input file with no trailing newline created by:
$ cat testfile
lineone
linetwo^d^d

The following happens:

$ java -cp . ScannerTest
0 lineone
1 linetwo

This is what I'd expect. What's it do for you?
--
Mark Rafn da***@dagon.net <http://www.dagon.net/>

Sep 25 '06 #6
On Mon, 25 Sep 2006 10:03:55 -0700, da***@dagon.net (Mark Rafn) wrote:
>DemonWasp <jd****@msn.comwrote:
>>What I *was* asking was "how do I get the last line from a file, even
when there is no trailing whitespace?"

I can't repro the problem - help me understand what I'm missing. I'm using
the following test class:

import java.io.*;
import java.util.Scanner;
public class ScannerTest {
public static void main(String[] args) throws Exception {
if (args == null || args.length != 1) {
System.out.println("Specify filename.");
System.exit(1);
}

File input = new File(args[0]);
InputStream is = new FileInputStream(input);

int lineNum=0;
for (Scanner s = new Scanner(is); s.hasNextLine();) {
String line = s.nextLine();
System.out.println(lineNum++ + " " + line);
}
}
}

And input file with no trailing newline created by:
$ cat testfile
lineone
linetwo^d^d

The following happens:

$ java -cp . ScannerTest
0 lineone
1 linetwo

This is what I'd expect. What's it do for you?
You're not missing anything, your code is subtly different. I figured
out the problem.

In my code, I had:

for ( String ln=in.nextLine() ; in.hasNextLine() ; ln=in.nextLine() )

which works fantastically until it gets to the last line in the file.
The "increment" part of the for loop (ie. ln=in.nextLine()) goes and
gets the last line. Then the second part of the for loop checks
(in.hasNextLine()) and returns false - then it skips the body of the
loop.

This caused the following problems:
1) I missed the last line of input because the loop exited too early.
2) When I tried adding an ln=in.nextLine() statement after the for
loop, to gather the "missing" last line, I triggered a
NoSuchElementException because, clearly, I had already loaded the last
line in the file.

The solution is to make sure that the test is done BEFORE I read in
the next line. So the following code works perfectly:

while(in.hasNextLine()){
ln=in.nextLine()
}

Thanks to everyone for the help.
/DemonWasp

Sep 25 '06 #7
DemonWasp <jd****@msn.comwrote:
>I've been having some trouble getting the Scanner class to operate the
way I'd like.
Came back to read the OP to see what I'd missed. You misstate the problem.
It's not the Scanner doing the wrong thing, you're confused about how a for()
loop works.
>for ( Ln=In.nextLine() ; In.hasNextLine() ; Ln=In.nextLine() ) {
// Do stuff with Ln in here.
}
Remember,
for( a; b; c) { d }
is exactly translatable as
{ a; while (b) { d; c; }

I'm unwilling to put up with stupidly nonstandard naming, so I'll just pretend
your variables are lowercase. Your code is identical to:

ln=in.nextLine();
while (in.hasNextLine) {
// do stuff
ln = in.nextLine();
}

This is just wrong. You're getting line 0, then test for line n+1 before
processing line n and getting n+1. You'll blow up with empty input, and skip
processing the last line. You'll GET the last line, as the last part of
processing the previous, but your loop condition is now false, so you won't
process it.
>Unfortunately, this moves the "cursor" in the file down one line, and
returns the text skipped - probably not what I was trying to do. Also,
when it gets to the end of the file, hasNextLine() returns false (as
it should) and the loop finishes. Unfortunately, it's still left
precious information in the file!
Nope, it left the information in your ln variable.
>When I tell it to load the final line using nextLine(), it tries
advancing past the end of the file and gives me a
NoSuchElementException.
As it should. You already read the last line, you just haven't processed it
yet.
>How can I get that last line (preferably, using the Scanner class)? Is
it possible to specify that the EOF sequence is a delimiter - or would
that even work?
You _ARE_ getting the last line. you're just discarding it by getting it at
the end of your loop rather than the beginning. try the following:
in = new Scanner(input);
while (in.hasNextLine) {
ln = in.nextLine();
// do stuff
}
or (if you want your locals to conveniently go out of scope after the loop
for (in = new Scanner(input); in.hasNextLine; ) {
String ln = in.nextLine;
// do stuff
}
--
Mark Rafn da***@dagon.net <http://www.dagon.net/>
Sep 25 '06 #8

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

15 posts views Thread by Ridimz | last post: by
2 posts views Thread by Eric Lilja | last post: by
35 posts views Thread by RyanS09 | last post: by
6 posts views Thread by magix | last post: by
tolkienarda
14 posts views Thread by tolkienarda | last post: by
4 posts views Thread by guiromero | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.