Programming Resources
For Fun and Learning
Charles Cusack
Computer Science
Hope College
main

Python
C++

JAVA


PHP
SQL
Assignments

FileIO


DumbList.java

/**-----------------------------------------------------------------------------
 * DumbList.java
 * Written by Chuck Cusack
*     November,  2001
 * Modified September, 2005
 *-----------------------------------------------------------------------------
 * A class that stores a dumb list of integers and floats
 * Like most of the code the students hand in, this is "self-documenting".
 * As if.
 *
 * The point of the class is to further demonstrate how to read and write
 * both text and binary files.
 *
 * The list consists of 'listSize' ints and floats.
 * There are methods to read and write the list to a file.  The format is:
 *      listSize,theInt[0],theFloat[0],theInt[1],theFloat[1],...
 *      theInt[listSize-1],theFloat[listSize-1]
 * For example, the file could be:
 *
 * 4 2 2.3443 3 .0000234 10234 1.23 34863496 1234.334
 *
 * For binary files, there is obviously no spacing between the elements.
 * For text files, the items are delimited by spaces, tabs, or newlines.
 *
 * It is important to realize that in Java, there are several ways of performing
 * File I/O.  This class presents a few methods of both reading and writing
 * to both text and binary files.  No claim is made that it is the best way.
 * 
 * 
 * When you are done looking at this code, you should look at the Java
 * API for the following clases:
 *     // For Text I/O
 * FileReader, FileWriter
 * PrintWriter
 * BufferedReader, BufferedWriter
 * 
 *    // For binary I/O
 * FileInputStream, FileOutputStream
 * DataInputStream, DataOutputStream
 * 
 *-----------------------------------------------------------------------------
 */
import java.awt.*;
import java.io.*;
import java.util.*;
//-----------------------------------------------------------------------------
public class DumbList {

  //---------------------------------------------------------------------------
  int listSize;
  int theInt[];
  float theFloat[];
  String inputFilename, outputFilename;
  char inputType, outputType;

  //---------------------------------------------------------------------------
  public DumbList() {
       theInt=null;
       theFloat=null;
  }  
  //---------------------------------------------------------------------------
  // A main method to test our class
  public static void main(String[] args) {
        DumbList A=new DumbList();
        A.readInputFilename();
        A.readOutputFilename();
        A.readFileTypes();
        A.ReadList();
        A.WriteList();
        System.out.println("Done.");
  }
  //---------------------------------------------------------------------------
  public void readFileTypes() {
     try {
        byte[] filenameArray=new byte[50];
        inputType=' ';
        while(inputType!='b' && inputType!='t') {
           System.out.print("Enter input file type.  ");
           System.out.print("Output type will be the reverse.\n");
           System.out.print("Use 't' for text and 'b' for binary: ");
           System.in.read(filenameArray);
           inputType=(char) filenameArray[0];
           if(inputType=='b') {
             outputType='t';
           }
           else if(inputType=='t') {
             outputType='b';
           }
        }
     }
     catch(IOException e) {
        System.out.println("Don't know what, but something is wrong.");
     }
  }
  //---------------------------------------------------------------------------
  public void readInputFilename() {
     try {
        byte[] filenameArray=new byte[50];
        System.out.print("Input Filename: ");
        listSize=System.in.read(filenameArray);
        inputFilename=new String(filenameArray,0,listSize-1);
     }
     catch(IOException e) {
        System.out.println("Don't know what, but something is wrong.");
     }
  }
  //---------------------------------------------------------------------------
  public void readOutputFilename() {
     try {
        byte[] filenameArray=new byte[50];
        System.out.print("Output Filename: ");
        listSize=System.in.read(filenameArray);
        outputFilename=new String(filenameArray,0,listSize-1);
     }
     catch(IOException e) {
        System.out.println("Don't know what, but something is wrong.");
     }
  }
  //---------------------------------------------------------------------------
  public void ReadList() {
        if(inputType=='b') {
          ReadBinary();
        }
        else if(inputType=='t') {
          ReadText();
        }
      }
  //---------------------------------------------------------------------------
  public void WriteList() {
        if(outputType=='b') {
          WriteBinary();
        }
        else if(outputType=='t') {
          WriteText();
        }
      }
  //---------------------------------------------------------------------------
  public void ReadBinary() {
      // File I/O can throw nasty exceptions, and they MUST be caught.
      // Thus, either the method has to throw the possible exceptions
      // that might be generated, or it has to deal with them itself.
      // In this case, we deal with it.  To do this, we use the regular
      // try-catch block.
      //
      try {
         // A few comments in general before we get to the actual code:
         //
         // Generally when we do File I/O, we use two classes to give us access
         // to the file.  The first gives us access to the file, and the second
         // one gives us convenient methods to write to the file.  It looks
         // kind of like this:
         //    DataStream ---> FileStream --> File
         // We write to/read from the DataStream (or similar class), which
         // writes to the FileStream, which writes to the file.
         // This is done for a few reasons:
         // 1) It is usually more efficient to use things like DataStreams and
         //    BufferedReaders/PrintWriters than to write directly to FileStreams
         //    and FileReaders.
         // 2) The DataStreams and BufferedReaders/PrintWriters generally provide
         //    more convenient methods to perform file I/O.
         // Now onto the specifics of this code.
         
         // To begin with, we use a FileInputStream to read from the file.
         // This is used when you want to read a file as a binary file.
         // As we will see, a FileReader is used for text files.
         //
         FileInputStream fStream=new FileInputStream(inputFilename);
         // We use the DataInputStream wrapped around the FileInputStream
         // for efficiency and because it provides nice methods of reading 
         // primitive types.  
         //
         // It is usual in Java file I/O to use two streams/readers to access
         // a file.  Generally one gives us access to the file, and the other
         // makes doing the I/O faster and/or easier to program.
         //
         DataInputStream dStream=new DataInputStream(fStream);

         // Start by reading in the size of the lists.
         listSize=dStream.readInt();
         
         // Now get arrays to store the data.
         theInt=new int[listSize];
         theFloat=new float[listSize];
         
         // Read the ints and floats.
         for(int i=0;i<listSize;i++) {
             theInt[i]=dStream.readInt();
             theFloat[i]=dStream.readFloat();
         }
         // Always close a stream when you are done.  It's like putting
         // the toilet seat down in the bathroom.  You might get away
         // with it, but it might come back to haught you later...
         dStream.close();
      }
      // Here is where we catch any exceptions that are thrown.
      // Notice we only catch an IOException.  This is the only
      // one we must catch in this case.
      catch(IOException e) {
        System.out.println("Some File I/O problem occured");
      }
  }
  //---------------------------------------------------------------------------
  public void ReadText() {
      try {
        // Since we are reading a text file, we start by using a FileReader.
        FileReader fRead=new FileReader(inputFilename);
        // For efficiency and convenience, we wrap the FileReader in a 
        // BufferedReader.  In this case, we read the whole file in as a 
        // character array, and use a tokenizer to parse it into the data we want.
        // This is not the only way to do it, but it works.
        BufferedReader bRead=new BufferedReader(fRead);

        // We make the (perhaps false) assumption that there are less than
        // 1000 characters in the file.  Again, there are better ways to do
        // this, but for now it will work.
        char theInput[]=new char[1000];
        
        // Read the data in.
        int numberChars=bRead.read(theInput);
        
        // We can close the file, because we have done all the reading we
        // intend to.
        bRead.close();
        
        // Get a StringTokenizer based on the input array.
        String theData=new String(theInput,0,numberChars-1);
        StringTokenizer st=new StringTokenizer(theData," \n\t\r");

        // Get the size of the list, which should be the first
        // token.
        listSize=Integer.parseInt(st.nextToken());

        // Get the lists to store the numbers.
        theInt=new int[listSize];
        theFloat=new float[listSize];

        // If there aren't 2*listSize tokens left, there is something
        // wrong with the file, so we give up.
        if(st.countTokens() != 2*listSize) {
            System.out.println("File corrupted.");
        }
        else {
            // Convert the tokens to ints and floats.
            for(int i=0;i<listSize;i++) {
                theInt[i]=Integer.parseInt(st.nextToken());
                theFloat[i]=Float.parseFloat(st.nextToken());
            }
        }
    }
    // Here we only catch IOExceptions.
    // We should probably also catch NumberFormatExceptions, since
    // the Integer.parseInt and Float.parseFloat will throw these
    // if the input file is not formatted correctly.
    // If this happens, our program will simply crash.
    catch(IOException e) {
       System.out.println("Some File I/O problem occured");
    }
  }
  //---------------------------------------------------------------------------
  public void WriteText() {
    try {
        // We use a FileWriter since we are writing text.
       FileWriter oStream=new FileWriter(outputFilename);
       // We wrap the FileWriter with a PrintWriter for efficiency, and 
       // because, as with the other cases, it provides some nice methods
       // for writing primitive types, Strings, and other things.
       PrintWriter pWriter=new PrintWriter(oStream);

       // We start by writing the size of the list out, including
       // the newline character.
       pWriter.write(listSize+"\n");
       // We then write out the lists.  Notice that we must include the
       // whitespace when we write, since otherwise the numbers will all
       // run together, and then we can't read them back in properly.
       for(int i=0;i<listSize;i++) {
           pWriter.write(theInt[i]+" "+theFloat[i]+"\n");
       }
       // As always, we close the writer when we are done.
       pWriter.close();
    }
    catch(IOException e) {
       System.out.println("Some File I/O problem occured");
    }
  }
  //---------------------------------------------------------------------------
  public void WriteBinary() {
    try {
        
        // Hopefully by now, you can figure out what we are doing with the
        // two streams.  The FileOutputStream and DataOutputStream are useful
        // for binary files.
       FileOutputStream fStream=new FileOutputStream(outputFilename);
       DataOutputStream dStream=new DataOutputStream(fStream);

       // We write out the size of the list
       dStream.writeInt(listSize);
       // We write out the lists.  Notice we do NOT include space between
       // the numbers, because with binary files, we know the length of each,
       // so when we read back in, the data types determines how much data
       // to read.
       for(int i=0;i<listSize;i++) {
           dStream.writeInt(theInt[i]);
           dStream.writeFloat(theFloat[i]);
       }
       // Closing the stream as usual.
       dStream.close();
    }
    catch(IOException e) {
       System.out.println("Some File I/O problem occured");
    }
  }
  //---------------------------------------------------------------------------
}