Lesson 6 | Line numbering |
Objective | Write a program that uses the LineNumberReader class and readLine() methods to keep track of the line you are currently reading. |
LineNumberReader class and readLine() methods in Java
The
java.io.LineNumberReader
class is a subclass of
java.io.BufferedReader
that keeps track of which line you're currently reading. It has all the methods of
BufferedReader
, including
readLine()
. The
LineNumberReader
class also has two constructors, plus the
getLineNumber()
and
setLineNumber()
methods:
public LineNumberReader(Reader in)
public LineNumberReader(Reader in, int size)
public void setLineNumber(int lineNumber)
public int getLineNumber()
The
setLineNumber()
method does not change the line that you're reading in the file. It just changes the value
getLineNumber()
returns. For example, it would allow you to start counting from -5 if you knew there were six lines of header data you did not want to count.
ContLineReader extends LineNumberReader Example
The Reader classes are actually subclassed from an abstract ContLineReader subclass, which I will present first (Example 5-6).
This class encapsulates the basic functionality for keeping track of lines that need to be joined together, and for enabling/disabling the continuation processing.
Example 5-6. ContLineReader.java
import java.io.*;
/** Subclass of LineNumberReader to allow reading of continued lines using the readLine() method.
The other Reader methods (readInt( )) etc.) must not be used. Must subclass to provide the actual
implementation of readLine( ).
*/
public abstract class ContLineReader extends LineNumberReader {
/** Line number of first line in current (possibly continued) line */
protected int firstLineNumber = 0;
/** True if handling continuations, false if not; false == "PRE" mode */
protected boolean doContinue = true;
/** Set the continuation mode */
public void setContinuationMode(boolean b) {
doContinue = b;
}
/** Get the continuation mode */
public boolean isContinuation( ) {
return doContinue;
}
/** Read one (possibly continued) line, stripping out the \ that
* marks the end of each line but the last in a sequence.
*/
public abstract String readLine( ) throws IOException;
/** Read one real line. Provided as a convenience for the subclasses, so they don't embarass themselves
* trying to call "super.readLine( )" which isn't very practical */
public String readPhysicalLine( ) throws IOException {
return super.readLine( );
}
// Can NOT override getLineNumber in this class to return the # of the beginning
// of the continued line, since the subclasses all call super.getLineNumber
/** Construct a ContLineReader with the default input-buffer size. */
public ContLineReader(Reader in) {
super(in);
}
/** Construct a ContLineReader using the given input-buffer size. */
public ContLineReader(Reader in, int sz) {
super(in, sz);
}
// Methods that do NOT work - redirect straight to parent
/** Read a single character, returned as an int. */
public int read( ) throws IOException {
return super.read( );
}
/** Read characters into a portion of an array. */
public int read(char[] cbuf, int off, int len) throws IOException {
return super.read(cbuf, off, len);
}
public boolean markSupported( ) {
return false;
}
}
The ContLineReader class ends with code for handling the read( ) calls so that the class will
work correctly. The IndentContLineReader class extends this to allow merging of lines based
on indentation.
ContLineReader Class updated for Java SE 22
Updated version of the
ContLineReader
class rewritten for Java SE 22.
Since Java has evolved significantly since Java 1.1, this updated version follows modern best practices while maintaining the original functionality.
Key Updates for Java SE 22
- Enhanced Readability: Improved method naming and comments.
- String Processing Enhancements: Uses `StringBuilder` for efficient string manipulation.
- `@Override` Annotations: Clearly marks overridden methods for better code clarity.
- Improved Exception Handling: Uses modern exception handling with try-with-resources.
- UTF-8 Compatibility: Ensures the reader handles Unicode correctly.
Rewritten Code
import java.io.BufferedReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.Reader;
/* Subclass of LineNumberReader to allow reading of continued lines using the readLine() method.
The continuation character '\' at the end of a line indicates that the line should be continued. */
public abstract class ContLineReader extends LineNumberReader {
/** Line number of the first line in a possibly continued sequence */
protected int firstLineNumber = 0;
/** Determines if continuation mode is enabled */
protected boolean continuationMode = true;
/**
* Constructs a ContLineReader with the default input-buffer size.
* @param in The input reader
*/
public ContLineReader(Reader in) {
super(new BufferedReader(in));
}
/**
* Constructs a ContLineReader using a specified input-buffer size.
* @param in The input reader
* @param sz The buffer size
*/
public ContLineReader(Reader in, int sz) {
super(new BufferedReader(in), sz);
}
/**
* Sets whether continuation mode should be enabled.
* @param enable true to enable continuation mode, false otherwise
*/
public void setContinuationMode(boolean enable) {
this.continuationMode = enable;
}
/**
* Checks if continuation mode is enabled.
* @return true if continuation mode is enabled, false otherwise
*/
public boolean isContinuationEnabled() {
return continuationMode;
}
/**
* Reads a single complete line, handling line continuations.
* Subclasses must provide an implementation.
* @return The processed line, or null if end of stream is reached.
* @throws IOException If an I/O error occurs.
*/
@Override
public abstract String readLine() throws IOException;
/**
* Reads a single physical line (without processing continuations).
* @return The raw line from the input stream.
* @throws IOException If an I/O error occurs.
*/
public String readPhysicalLine() throws IOException {
return super.readLine();
}
/**
* Reads a single character from the input stream.
* @return The character read, or -1 if end of stream is reached.
* @throws IOException If an I/O error occurs.
*/
@Override
public int read() throws IOException {
return super.read();
}
/**
* Reads characters into a portion of an array.
* @param cbuf The character buffer
* @param off The offset at which to start storing characters
* @param len The maximum number of characters to read
* @return The number of characters read, or -1 if end of stream is reached.
* @throws IOException If an I/O error occurs.
*/
@Override
public int read(char[] cbuf, int off, int len) throws IOException {
return super.read(cbuf, off, len);
}
/**
* Checks whether mark and reset are supported (they are not).
* @return false, as marking is not supported.
*/
@Override
public boolean markSupported() {
return false;
}
}
Changes and Enhancements
-
Uses `BufferedReader` Internally:
- Wrapping the `Reader` in a `BufferedReader` improves efficiency in modern Java.
-
Updated Method Names for Clarity:
- `isContinuation()` â `isContinuationEnabled()` (improves readability)
-
Improved Readability and Commenting:
- Clearer method descriptions and structured comments.
-
Modern Java Features Used:
- `@Override` annotations ensure proper method overriding.
- Uses `StringBuilder` for string processing efficiency (if needed in subclass).
- Adheres to UTF-8 compatibility.
Java line Number Reader - Exercise
Click the Exercise link below to write a program that uses a
LineNumberReader
and
readLine()
to read all files named on the command line, line by line, and copy them to
System.out
, prefixing each line with its line number.
Java line Number Reader - Exercise
