INFORMATION & COMPUTER SCIENCE DEPARTMENT, KFUPM

ICS102, SECTIONS 52, 54 & 55  (001 Semester)

INTRODUCTION TO COMPUTING

LAB  #12 String and File Processing

 

Instructor: Bashir M. Ghandi

 


Objectives:

To gain experience with:

 

1.  The String class

String processing is one of the most common applications of computers.  Java recognizes this fact, and therefore provides a String class that has many methods that can be used to process or manipulate strings

 

The following table shows some of the methods of the String class.  For a complete list of methods, check the JDK documentation:

method

description

myString = "examples"

int length()

returns the number of characters in this String.

int i = myString.length(); 
// i = 8
String toUpperCase()

returns a new String, representing the Upper-case equivalent of this String.

String upper=myString.toUpperCase(); 
// upper == "EXAMPLES" 
String toLowerCase()

returns a new String, representing the lower-case equivalent of this String.

String lower=myString.toLowerCase();
// lower == "examples" 
boolean equals(String s)
Boolean equalsIgnoreCase
           (String s)

returns true if the argument has the same length, and same characters as this String.

the second version ignores the case.

if (myString.equals("EXAMPLES") )
// false
int compareTo(String s)
int compareToIngoreCase
        (String s)

returns positive number, 0, or negative number if this String is lexicographically greater than, equal to or less than the argument respectively. 

if (myString.compareTo("Yes")>0 )
// true
char charAt(int index)

returns the char in this String, at the index position passed to the method. Note: Index positions always start at 0

char c = myString.charAt(6);
// c = ‘e’
int indexOf(int ch)
int lastIndexOf(int ch)
//also overloaded to 
accept String parameter

finds the first / last occurrence of a character or substring within this string, and returns the index. If the substring or char is not found -1 is returned.

int i = myString.indexOf("amp");
// i == 2
if (myString.indexOf("Y") > 0)
// returns -1 and is false
String substring
        (int from)
String substring
      (int from, int to)

returns a part of the original String starting from the fromIndex to the end of the string or up to but not including toIndex if one is given. 

String s=myString.substring(5)
// returns "ample" and "les"
String s=myString.substring(2, 7);
// returns "les"
String trim()

returns a String, produced by removing any whitespace characters from the beginning and end of this string.

String s = “    125     “;
s = s.trim();
//returns  “124”
static String valueOf
   (any primitive type)

is a static method, that is overloaded for all the primitive data types, and returns a String representation of the argument.

String s = String.valueOf(3.14F);
// numbers to Strings "3.14"
String concat(String s)
//equivalent to + symbol

append the argument string at the end of this string.

String s = myString.concat(“ below”)
// returns “examples below”

Note:

Java treats String as a special class in the sense that it has features that other Java classes do not have.  Some of these features are:

·         A String object can be created without using the new keyword.  For example,

String name = new String(“Bashir Ghandi”);

can be written simply as:

String name = “Bashir Ghandi”;

 

·         The plus operator ‘+’ can be used to append strings.  Example:

String fullName = “Bashir”+” Ghandi”;

 

2.  String Tokenizer.

The readLine() method of the BufferedReader object reads an entire line at a time.  However, there are many situations where we would like to break the line into individual words (called tokens) for further processing.  For example, if we read the string:

“996502     10    15    20”

we would like to break the string into the following:

“996502”    “10”  “15”  “20”

so that we can call the appropriate parser method to convert the tokens to numbers.

 

To achieve this, Java provides the class, StringTokenizer in the java.util package.

To use this class, we need to first create its object using of the constructors.

 

The following table shows the constructors and the main methods of the StringTokenizer class.

constructors and methods

description

StringTokenizer(String str)

Assumes white space as delimiters (“ \t\n\r”)

StringTokenizer(String str, String delim)

Uses the characters in the second argument as delimiters.

StringTokenizer(String str, String delim,
               boolean returnDelims)

If the third argument is true, include the delimiters as part of the tokens.

String nextToken()
String nextToken(String delim)

Returns the next token from this tokenizer’s string

boolean hasMoreTokens()

Tests if there are more tokens from this tokenizer's string

int countTokens()

Returns the number of tokens remaining in this tokenizer’s string.

 

Example 1: The following program outputs the tokens in a string provided by the user.

import java.io.*;

import java.util.*;

 

class TokenizerExample {

    static BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));

 

    public static void main(String[] args) throws IOException {

            int numberOfTokens=0;

     

        System.out.println("Input a string ");

        String line = stdin.readLine();

       

            StringTokenizer data = new StringTokenizer(line);

 

            numberOfTokens = data.countTokens();

            System.out.println("Number of tokens = " + numberOfTokens + "\n");

     

            for (int i=0; i < numberOfTokens; i++) {

                  System.out.println(data.nextToken());

          }

      }

}

 

Example 2:  The following example shows how StringTokenizer may be used to process numbers.  It reads a requence of numbers typed on one line, separated by comma or spaces and prints the average and those values below average.

import java.io.*;

import java.io.*;

import java.util.*;

 

class TokenizerExample2 {

    static BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));

 

      public static void main(String[] args) throws IOException {

            int numberOfTokens=0;

            int[] numberArray;

            int total=0;

            double average;

     

            System.out.print("Input list of integers separated by commas or space: ");

            StringTokenizer data = new StringTokenizer(stdin.readLine()," ,");

 

            numberOfTokens = data.countTokens();

            System.out.println("Number of tokens = " + numberOfTokens + "\n");

            numberArray = new int[numberOfTokens];

     

            for (int i=0; i < numberOfTokens; i++) {

                numberArray[i] = Integer.parseInt(data.nextToken());

                System.out.println(numberArray[i]);

                total = total+numberArray[i];

            }

            average = (double)total/numberOfTokens;

            System.out.println("---------\n" + total + " (average = " +average+ ")");

            System.out.println("\nValues below average are:");

            for (int i=0; i<numberOfTokens; i++)

                  if (numberArray[i] < average)

                        System.out.println(numberArray[i]);      

      }

}  

 

3.  File Processing.

The applications we have written so far read input from the keyboard and displayed output on the screen.  These methods of input/output are inadequate for programs that creates large amount of data.  In this section we examine how input may be read from a file and how output may be written to a file using a number of classes in the java.io package.

 

3.1  Reading input from a file.

To read input from a file, we make use of the following classes:

FileInputStream:  This is used to create a stream source (an object from which streams can be read.  For example:

FileInputStream inFile = new FileInputStream(“mydata.txt”);

 

This opens the file “mydata.dat” for reading and associates it with the inFile object.

If the file does not exists, a FileNotFoundException is thrown.

If the file is not in the current folder, the full path of the file must be specified.

When specifying the full path of the file, it is better to use forward slash.  Example: “C:/workarea/mydata.txt”

The back slash can also be used, but double slash must be used for each slash.  Example:“C:\\workarea\\mydata.txt”

However, if the file name is being read from the user using a string variable, then only single slash is used.

 

InputSreamReader:  This (as explained before) is used to create an object which can be used to read one character at a time from a stream source.  Example:

InputStreamReader reader = new InputStreamReader(

new FileInputStream(“mydata.txt”));

 

BufferedReader:  This (as explained before) is used to create an object that can be used to read one line at a time from a stream reader (using its readLine() method).  Example:

BufferedReader in = new BufferedReader(

new InputStreamReader(

    new FileInputStream(“mydata.txt”)));

 

FileReader: This is a used to directly create a stream reader object from a file, effectively taking over the work of FileInputStream and InputStreamReader.  Thus, the declaration of the BufferedReader object obove can be simplified as follows:

BufferedReader in = new BufferedReader(new FileReader(“mydata.txt”));

 

Notes:

·         These classes throws IOException and/or FileNotFoundException if an error occurs.  Thus, we must either use try and catch to handle the possible exceptions or throw such exceptions.  FileNotFoundException is in fact a subclass of IOException, thus, unless there is a need to specifically handle it, handling IOException can suffice for it.

·         It is a good practice to always close files using the close() method after the reading (or writing) is completed.  If fact, sometimes it is necessary to do so, for example, when opening a file for input after it has been opened for output and vice-versa.

·         The BufferedReader object associated with a FileInputStream or FileReader has a method, ready(), that can be used to test if the file pointer has reach the end of the file.  This is very useful when reading all the lines in a file.

 

Example 3: The following example reads the content of a file, myinput.txt, and display it on the screen.

import java.io.*;

public class DisplayTextFile {

      public static void main(String[] args) {

         String line;

         int count = 0;

                     

         try {

            BufferedReader  in = new BufferedReader(new FileReader("myinput.txt"));

            while (in.ready()) {

                  line = in.readLine();

                  System.out.println(line);

                  count++;

            }

            System.out.println("\n"+count + " lines have been read from myinput.txt" );

            in.close();

         }

         catch(FileNotFoundException e) {

            System.out.println("Sorry, file myinput.tx was not found");

         }

         catch(IOException e) {

             System.out.println("Error reading from file, input.txt");

         }

      }

}

 

Example 4:  The following example reads integers from the file, integerdata.txt, and prints the sum, average and list of values below average.

import java.io.*;

import java.util.*;

class ProcessFileOfInteger {

    public static void main(String[] args) throws IOException {

        BufferedReader in = new BufferedReader(new FileReader("integerdata.txt"));

        int numberOfTokens = 0, number, count=0, sum=0;

        StringTokenizer dataLine;

        String line; 

        while (in.ready()) {

           line = in.readLine();

           if (line != null) {     

                  dataLine = new StringTokenizer(line);

                  numberOfTokens = dataLine.countTokens();

                  for (int i=0; i < numberOfTokens; i++) {

                        number = Integer.parseInt(dataLine.nextToken());

                        sum+=number;

                        count++;   

                        System.out.print(number + " ");

                  }

                  System.out.println();

           }

        }

        System.out.println("----------------\nCount of numbers: "+count);

        System.out.println("Sum of numbers: "+sum);

        System.out.println("Average of numbers: "+sum/(double)count);

        in.close();

   }

}

 

3.2  Writing to a file:

To write output to a file, we make use of the following classes:

FileOutputStream:  This is used to create a stream target (an object into which streams are written).  It has two constructors that are used as follows:

FileOutputStream outFile = new FileOutputStream(“result.txt”);

or

FileOutputStream outFile = new FileOutputStream(“result.txt”, true);

 

This opens the file “result.txt” for writing.  If the file exists, its content is deleted so that the new output will effectively overwrite the old content of the file. 

 

If the second parameter of the second constructor is true, the file is opened for appending.  i.e. the content of the file is NOT deleted, rather any new data is written at the end of the file.

 

In either case, if the file does not exist, it is created.  If it cannot be created for some reason, or if it exist but cannot be opened for some reason, a FileNotFoundException is thrown.

 

OutputStreamWriter:  This is used to create an object that can be used to write one character at a time to a stream target object.

Example:

                OutputStreamWriter writer = new OutputStreamWriter(

  new FileOutputStream(“result.txt”));

 

PrintWriter:  This is used to create an object that can be used to print output to an output writer.  The object has print and println methods that are overloaded for all data types.  Example:

PrintWriter out = new PrintWriter(

    new OutputStreamWriter(

        new FileOutputStream(“result.txt”)));

 

FileWriter:  This is used to create stream writer directly to a file.  Thus, the PrintWriter object creation above can be simplified as:

PrintWriter out = new PrintWriter(new FileWriter(“result.txt”));

or

PrintWriter out = new PrintWriter(new FileWriter(“result.txt”, true));

 

Example 5: The following example read data from the file storylines.txt and append it to the file story.txt.

import java.io.*;

 

public class AppendText {

  

   public static void main(String[] args) {

      int count = 0;

      String line;

           

      try {

         BufferedReader  in = new BufferedReader(new FileReader("storylines.txt"));

         PrintWriter  out = new PrintWriter(new FileWriter("story.txt", true));

        

         while (in.ready()) {

            line = in.readLine();

            if (line != null) {

                  out.println(line);

                  count++;

            }

         }

         System.out.println(count+" lines have been appended to story.txt" );

         in.close();

         out.close();

      }

      catch(FileNotFoundException e) {

         System.out.println("Sorry, one or both files could not be found");

      }

      catch(IOException e) {

         System.out.println("Error handling files");

      }

   }

}

 

Example 6:  The following example reads ID numbers, names and grades of students in three exams contained in a file, examdata.txt and computes the average of each student.  It prints the output on both the screen and the file, result.txt.

import java.io.*;

import java.util.*;

 

class ProcessExamScore {

 

    public static void main(String[] args) throws IOException {

        BufferedReader in = new BufferedReader(new FileReader("examdata.txt"));

        PrintWriter out = new PrintWriter(new FileWriter("result.txt"));

       

        String line, name, iDNumber;

        double exam1, exam2, exam3, average;

        StringTokenizer dataLine;

       

        line = in.readLine();

        while (line != null) {

            dataLine = new StringTokenizer(line, "|");

            iDNumber = dataLine.nextToken();

            name = dataLine.nextToken();

            exam1 = Double.parseDouble(dataLine.nextToken().trim());

            exam2 = Double.parseDouble(dataLine.nextToken().trim());

            exam3 = Double.parseDouble(dataLine.nextToken().trim());

            average = (exam1 + exam2 + exam3)/3;

 

   System.out.println(iDNumber+"\t"+name+"\t"+exam1+"\t"+exam2+"\t"+exam3+"\t"+average);

   out.println(iDNumber+"\t"+name+"\t"+exam1+"\t"+exam2+"\t"+exam3+"\t"+average);

            line = in.readLine();

       }

       in.close();

       out.close();

   }

}

 

Note: If the delimiter of a StringTokenizer does not include space, then the trim() method must be applied to the tokens to remove spaces before passing them to a parser methods.  Failure to do this will make the parser methods to throw NumberFormatException.

 

4.  Assignments

1.        Modify example 4 (ProcessFileOfInteger.java) so that it prints the output both on the screen and in a file, result2.txt

 

2.        Modify example 6 (ProcessExamScore) so that it also prints the average of each quiz on both the screen and in the file, result.txt.

3.        Midify Example 1 (DisplayTextFile) so that it also print on the screen, the number of words, the longest word, the shortest word and the average length of a word in the file.  You may add more words in the file.

 

5.  Home Work

1.       Write an application, FrequencyTable, that reads the data in integerdata.txt file and prints a frequency table both on the screen and in the file frequency.txt as shown below: