Reader class

 

See the following classes which use Reader's methods:  FileReader class,  CharArrayReader class, 

InputStreamReader class,  FilterReader class,  PushBackReader class,  StringReader class, 

PipedReader class,  BufferedReader class,  and  LineNumberReader class

 

  The nine Reader methods (examples below) are:

 

.mark( readAheadLimit )  Mark the present position in the stream.

.markSupported( ) Tell whether this stream supports the mark(...) operation.

.read( )  Read a single character, returning it in the low end two bytes of an int.

.read( char[ ] )  Read characters into a char array.

.read( char[ ], offset, len)  Read characters into a portion of a char array.

.ready( ) Tell whether this stream is ready to be read.

.reset( )  Reset the stream.

.skip( n )  Skip over n characters in the stream.

.close( ) Close the stream.

 

  Reader is the abstract class which defines the nine basic methods for all of the character input stream classes named above.  They are all subclasses of Reader. 

 

  Methods defined in Reader will read character files in formats such as UTF-16 (returning two meaningful bytes per character) and UTF-8 (returning one meaningful byte per character).  They can also read ASCII files and other 8-bit local machine encodings, because of the fact that such 8-bit encodings "fit" under UTF-8. 

 

  The general scheme of Reader's read(...) methods is that they return the meaningful byte(s) of the characters in the right-hand or lower end of an int. To signify end-of-stream, minus one is returned in that int.

 

 

  All of these methods except markSupported(...) can throw IOExceptions.  Using them requires try-catch blocks. 

 

 

int  .read( )  method

 

  This method reads one character.  It returns an int containing the desired char in its lower two bytes.  At end of stream the value of the int returned is -1.  Any read operations attempted after end of stream will also return -1.  The shorthand while statement below is commonly used to execute a read and test for end of the stream at the same time.  Assume that fr is already a valid FileReader object handle:

 

 import java.io.*; 

 

 int x; 

 while (( x = fr.read( )) != -1 ) {

     // do things

}

 

The shorthand approach above is equivalent to these longer statements:

 

 import java.io.*; 

 

while ( true) {

    int c = fr.read( );

    if ( c != -1 ) {

        // do things

    }

else break;

}

 

  Results are usually cast to char for printing.  i.e. Assume x is the int which was returned here:

 

  System.out.print( String.valueOf( (char) x ) );

 

  If the int which is returned is not cast to char then its integer value will print.  i.e.

 

import java.io.*;

 

StringReader sr = new StringReader( "ABCDEFGHIJ" );

int x = 0;

x = sr.read( );

System.out.println( "Uncast int value prints like: \t\t" + x );                          // prints 65

System.out.println( "When cast to char it prints like: \t" + (char) x  );         // prints A

System.out.println( x );                                                                                       // prints 65

System.out.println( String.valueOf( (char) x ) );                                              // prints A

 

 

  Casting ints to chars for printing. Similarly, the snippet below, which provides casting of the int, prints ABCDEFGHIJ. 

The second snippet, with no casting, prints 65666768697071727374.

 

import java.io.*;

 

Reader in = new StringReader( "ABCDEFGHIJ" );

for ( int x = 0; x < 10; x++ ) {

    int y = in.read( );

   System.out.print( (char)  y  );                          // prints ABCDEFGHIJ

 }

 

 

 Reader in = new StringReader( "ABCDEFGHIJ" );

 for ( int x = 0; x < 10; x++ ) {

      int y = in.read();

     System.out.print(  y  );                    // prints 65666768697071727374

 }

 

 

int  .read( char[ ] )  method

 

  Reading a desired number of characters.  This method reads as many characters as the declared length of the char[ ] c array, putting them into the array itself.  The snippet illustrates reading and printing exactly five characters at a time from a file. 

 

import java.io.*;

 

FileReader fr = new FileReader( new File( "myfile" ));

char[ ] c = new char[ 5 ];

int x;

while (( x = fr.read( c ) ) != -1 ) {

    System.out.println( c ); 

}

 

  The number of characters read is returned as an int.  The int will reflect the length of the array, until the second-to-last read operation, when it will then reflect however many bytes were in the last read operation which encountered some data to read.  The read operation after that, presumably the final one, will return a -1, signifying the end of the stream's source.

 

  You cannot depend upon the contents of the char array at end-of-stream time.  Its contents will be indeterminable.

 

 

  You cannot inaugurate buffering by specifying a length for the char array. Characters are still read one at a time into the array.  To get buffering, chain a BufferedReader.   see BufferedReader

 

 

int  .read( char[ ] , offset, len )  method

 

  This method can read one or multiple characters from the stream.  It attempts to read as many characters as int len, placing them into the char[ ] c array at the offset location defined by int off. Offsets begin with zero.
 
 After this snippet, the char array which was ABCDEFGHIJK  is altered and becomes ABC12345IJK.  It is then printed.  The five characters just read, which are 12345, now occupy positions inside the array starting at offset three.
 

import java.io.*;

 

StringReader sr= new StringReader( "123456789" );

int x = 0;

char[ ] c = { 'A','B','C','D','E','F','G','H','I','J','K'};

x = sr.read( c, 3, 5 );

System.out.println( c ); 

 

 You cannot do offset stream reading with this method.  The offset int off refers to where the characters will go in the array, not where they will be read from the steam. The stream's next characters are always read. Use skip(...) (below) if you wish to bypass characters in the stream.

 

  The number of characters actually read is returned as an int.  End of stream is again signified by returning -1.
 

  Specifying an off or len combination exceeding size of the the array will compile but will generate an IndexOutOfBoundsException.

 

 

boolean  .ready( )   method

 

  The various read(...) methods can block if the stream is in error, is in use, or is already at end of file.  This method returns true if the next read(...) is guaranteed not to block for input. i.e. Assume os is some valid character output stream handle:

 

if ( os.ready( ) ) {

   // your read operations go here

}

 

  Note that you cannot tell how many characters are ready to be read. At least one will generate a true.  However you may be trying to read multiple characters with methods such as read( char[ ] c ) or readLine( ). If you try to read more characters than remain, just those characters will be read.  No I/O error will be thrown.  The snippet below attempts to read six characters (the length of c) from a stream sr containing just two.  The two are placed into c without error and it prints the result 12CDEF.

 

import java.io.*;

 

char[ ] c = { 'A','B','C','D','E','F'};

try {

    StringReader sr = new StringReader( "12" );

    int x = 0;

    x = sr.read( c );

    System.out.println( c ); 

}

catch (Exception e) { System.out.println("Error: " + e);}

 

 

long  .skip( count )  method

 

  This method will force the stream to skip ahead as many characters as are specified in the parameter, as if it were actually reading the characters.  It returns in a long the number of characters actually skipped. 

 

The snippet skips the first eight characters in stream sr, which contains 123456789.  It then reads just the character 9, which it then prints. It also prints the returned long containing the number of characters skipped, to show that it is indeed 8.

 

import java.io.*;

 

 try {

    StringReader sr = new StringReader( "123456789" );

    int x = 0;

    long l1 = 8;                                         // define how many to be skipped

    long l2= sr.skip( l1 );                        // skip the first 8

    x = sr.read( );                     // read the 9th

    System.out.println( (char) x );  // print it

    System.out.println( l2 );                  // print the amount skipped

}

catch (Exception e) { }

 

 

  Determining a file’s size without reading it.  You can use skip(...) to determine a file's size. If instructed to skip more characters than exist in an as-yet unread file or stream, skip(...) will return the entire size of the file in characters.  The snippet tells you that there are 114 characters in a file containing this poem. Note that it counts  both end of line characters on each line, as there are only 106 readable characters.

 

Mary had a little lamb,

Its fleece was white as snow.

And everywhere that Mary went,

Her lamb was sure to go.

 

import java.io.*;

.

 try {

   FileReader fr = new FileReader( new File( "thatpoemfile" ));

    int x = 0;

    long l1 = 10000000;                                                           // Set skip at 10 million

    long l2= fr.skip(l1);                                          

    System.out.println(" Length of file is: " + l2); 

}

catch (Exception e) { }

 

  skip(...) is always supported for a character stream class even if reset( ) and mark( ) are not.

 

 The snippet below uses skip(...) to determine the length of a file which contains an unknown number of 40-character records.  It then reads the records into a two-dimensional char array where each row holds a record.  It does this by first invoking skip(...) past the end of the file to determine its length, so the array can be allocated.  Then the file is re-read.  Note that, if reset( ) were supported for FileReader streams, the single reset( ) statement (which is commented out below) would accomplish a reset for easy re-reading using the same FileReader stream object fr. Since this first FileReader stream cannot be reset to the beginning because reset( ) is not supported for FileReader, a second FileReader stream fr2 is simply created on the file, and the file is re-read using it. 

 

import java.io.*;

 

FileReader fr = null;

FileReader fr2 = null;

try {

    fr = new FileReader( "mycharfile" );

    int x;

    int row = 0;

    int rcdLength = 40;                                                           // rcdLength tells the length o f the records

    long fileLength = fr.skip(1000000);                                // skippng a million goes beyond the end

    char[ ][ ] fileArray = new char[ (int) fileLength ] [ rcdLength ];  // fileArray is result array - rows of rcds

    char[ ] c = new char[ rcdLength ];

    // fr.reset( );                                                        // this reset would replace having to use fr2

    fr2 = new FileReader( "mycharfile" );

    while (( x = fr2.read(c) ) != -1 ) {

        for ( int y = 0;  y < 5;  y++ ) {

            fileArray[ row ][ y ] = c[ y ];

        }

        System.out.println( c ); 

        row++;

    }

} catch (IOException ex) {  }

  finally {

    try {

        if (fr != null) {

            fr.close();

        }

        if (fr2 != null) {

            fr2.close();

        }

    } catch (IOException ex) {    }

}

 

 

void  .close( ) method

 

  This abstract method is actually implemented by all of Reader's subclasses but the syntax and results are always the same. See the last statement below:

 

import java.io.*;

 

FileReader fr = new FileReader( new File( "myfile" ));

int x;

while (( x = fr.read( ) ) != -1 ) {

    System.out.print( (char) x ); 

}

fr.close( );

 

  You cannot do further operations on a stream after it is closed or you will get an IOException.

 

  You may close streams more than once with no ill effects.

 

  Closing input streams is good convention and good coding, but it does not have missing data ramifications as it does on the output side.  For input, the close( ) method is not technically required.  For output, it should be considered necessary to flush final data from the output buffer.

 

 

marking methods

 

boolean  .markSupported( )  method

 

  This method will return false if a stream does not support use of the mark(...) method below, and true if it does.  The way it works is that the default implementation from Reader returns false.  If a class wants to support mark(...), it overrides this and returns true instead.

 

The Reader subclasses which support mark(...) are: BufferedReader , CharArrayReader,  FilterReader, LineNumberReader, PushBackReader and StringReader.  (Not supporting it are InputStreamReader, FileReader, and PipedReader.)

 

 This example prints false because InputStreamReader does not support mark(...).

 

import java.io.*;

 

 try {

    InputStreamReader isr = new InputStreamReader( new FileInputStream( "anyfile" ));

    System.out.println( isr.markSupported( ) );

}

catch (Exception e) { }

 

 

void  .mark( readAheadLimit )  method

 

This method only works for streams which support it. See markSupported( ) above. It "marks" the current position in the stream or file.

 

 The snippet takes a stream of 1234567890ABCDEFGHIJKLMNO and marks the position of the letter A.  It then reads the rest of the stream, does a reset on it, and resumes reading one character.  The next character read - and printed here - is the A because the reset only goes back to the last mark.

 

import java.io.*;

 

try {

     StringReader sr = new StringReader( "1234567890ABCDEFGHIJKLMNO" );

     long l1 = 10;                                      // define how many to be skipped

     long l2= sr.skip( l1 );                       // skip the first 10

     sr.mark( 1000000 );                          // mark the position of the 11th, the A

     char[ ] c = new char[ 5 ];                 // now read three groups of 5

     int x;

     while (( x = sr.read( c ) ) != -1 ) { 

          System.out.println( c ); 

     } 

     sr.reset( );                                                         // when done, reset back to the mark

     x = sr.read( );                                    // read again, getting the A

     System.out.println( (char) x );       // print it

 }

 catch (Exception e) { }

 

If you attempt to mark(...) a stream which does not support it, you will get an IOException.

 

The int parameter readAheadLimit is supposed to put a limit on how many characters can be read after the mark(...) operation while still preserving the validity of the mark point. Results are unpredictable if that limit is exceeded by subsequent reads. The reads may succeed.  Or you may get null returns from your reads.  Or you can get a "Mark invalid" IOException. In practice readAheadLimit should be set to a very high number - larger than the file or stream size - if it not to be used. See the above example where this is done. 

 

 

void  .reset( ) method

 

 This method will reset the stream to the last mark.

 

The Reader subclasses which support mark(...) are: BufferedReader , CharArrayReader,  FilterReader, LineNumberReader, PushBackReader and StringReader.  (Not supporting it are InputStreamReader, FileReader, and PipedReader.)

 

StringReader, CharArrayReader  allow marking for reset( ) and also resetting to the beginning of a stream without doing a mark(...). 

 

BufferedReader require a mark(...) first and will throw a "Stream not marked" IOException if reset( ) is invoked on them without a mark(...).

 

  The example below sets a mark halfway through a stream, after five characters of ABCDE12345 have been read.  Later, after end-of-stream, it does a reset( ) which resets the stream to that point. Another while loop reads and prints the stream again.  But because of the presence of the reset to the mark which is located after the E, only 12345 is read and printed the second time.

 

char[ ] c = { 'A', 'B', 'C', 'D', 'E', '1', '2', '3', '4', '5'} ;

CharArrayReader car = new CharArrayReader( c );                         

int x;

int y = 0;

try {

     while ( (x = car.read( ) ) != -1 ) { 

         y++;

         if (y==5) car.mark(1000000);       // set the mark at the E

         System.out.print( (char) x );      // will print entire stream

      }

      car.reset( );                                      // reset the stream when done reading

      while ( (x = car.read( ) ) != -1 ) {     // read again, now beginning at the reset point

          System.out.print( (char) x );     // will print only ABCDE

      }

}

catch (Exception e) { }