the play's the thing


the funny thing is that to become a truly great programmer our scriptwriting should become as hackneyed as possible. to become a great hacker we must become great hacks.

Files

Streams

Applets

Vectors

Arrays

Strings

Hashtables

Trees

How To Build Your Very Own HTML Parser


package com.knownspace.tools;

import java.io.File;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class Copy
   {
   public static void copyFile(File fromFile, File toFile)
      throws IOException
      {
      /*
      Copy fromFile to toFile, overwriting toFile if it already exists.

      Throw IOException if there's any problem reading or writing the file.
      */

      //open the source and destination streams for reading and writing
      FileInputStream from = null;
      FileOutputStream to = null;
      try
         {
         from = new FileInputStream(fromFile);
         to = new FileOutputStream(toFile);

         byte[] buffer = new byte[8192];
         int bytesRead = from.read(buffer);
         while(bytesRead != -1)
            {
            to.write(buffer, 0, bytesRead);
            bytesRead = from.read(buffer);
            }
         }

      //close the streams, even if exceptions are thrown
      finally
         {
         if (from != null)
            {
            try
               {
               from.close();
               }
            catch (IOException ignored)
               {}
            }
         if (to != null)
            {
            try
               {
               to.close();
               }
            catch (IOException ignored)
               {}
            }
         }
      }
   }


package com.knownspace.tools;

import java.io.IOException;
import java.io.BufferedReader;
import java.io.FileReader;

public class StringTools
   {

   //java's standard enf of file flag
   public static final int END_OF_FILE = -1;

   public static String convertIntToString(final int numDigits, int integer)
      {
      /*
      Convert a positive integer to a numDigits-digit leading-zeros
      digit string and return the string.
      */

      if (integer < 0)
         return "cannnot handle negative numbers";

      //find the digits of integer from least to most
      int powerOfTen = 10;
      StringBuffer numberString = new StringBuffer("");
      for (int i = 0; i < numDigits; i++)
         {
         int remainder = integer % powerOfTen;
         int digit = (int) (remainder * 10 /powerOfTen);
         numberString.append(digit);

         integer -= remainder;
         powerOfTen *= 10;
         }

      //return the reverse of the digit string
      return numberString.reverse().toString();
      }

   public static String convertFileToString(final String fileName)
      throws IOException
      {
      /*
      Return a string of all the characters in the given text file.
      */

      BufferedReader stream = new BufferedReader(new FileReader(fileName));
      StringBuffer inString = new StringBuffer("");
      int character = stream.read();
      while (character != END_OF_FILE)
         {
         inString.append((char) character);
         character = stream.read();
         }
      stream.close();

      return inString.toString();
      }
   }


import Copy;
import StringTools;

import java.io.IOException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

import java.util.Vector;
import java.util.Hashtable;
import java.util.Enumeration;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import java.util.Locale;

public class FileSaver implements Runnable
   {
   /*
   Scan a directory for any new .htm files
   and store copies of those files
   as numbered .jpg files in numbered subdirectories
   of another directory.

   Constructors and Methods:
   -------------------------
   public static void main(String[] commandLineArguments)

   public FileSaver(String[] arguments)
      Initialize a new FileSaver object.

   public void start()
      Start a new thread.

   public void stop()
      Stop the thread.

   public void run()
      Copy all relevant files until told to stop.

   private void checkDirectories()
      Check that the given directories
      are legal for reading and writing.

   private void copyFiles(File sourceDirectory,
      File destinationDirectory)
      Copy all files in sourceDirectory
      matching the filter criteria
      to destinationDirectory.

   private File[] filterFiles(File sourceDirectory)
      Capture all sourceDirectory files
      matching the filter criteria.

   private long getLastModifiedTime(File[] files,
      final long lastModifiedTime)
      Find the modification time of the most recently modifed
      file in an array of files.

   private void copy(File fromFile)
      Copy file fromFile.
      If it has been copied before, only copy it again
      if it has changed since then.

   private File nameNextCopy()
      Decide what to name the next copy and where to place it
      and return the new filename.

   private void cleanTable(Hashtable table)
      Remove any files in the hashtable table that have vanished.


   Calling Sequence:
   -----------------
   public void main()
      public FileSaver()
      public void start()
   public void run()
      private void checkDirectories()
      private void copyFiles()
         private File[] filterFiles()
         private long getLastModifiedTime()
         private void copy()
            private File nameNextCopy()
            private void cleanTable()
   public void stop()

   See Also:
   ---------
   This class uses class Copy to do the file copying.
   This class uses class StringTools
   to convert integers to string suffixes.
   */

   //the source and destination directories
   private File sourceDirectory, destinationDirectory;

   //the current destination subdirectory
   private File destinationSubDirectory;

   //the suffix number of the current destination subdirectory
   private int subDirectoryNumber;

   //the suffix number of the current file copy
   private int fileNumber;

   //the modification time of the most recently modified file
   //in the source directory
   private long lastModifiedTime;

   //a table recording copied files
   //and their destination filenames
   private Hashtable filesCopiedTable;

   //the thread to copy files forever
   private Thread thread;

   //the thread controller
   private boolean stop;

   //time (in milliseconds) to sleep
   //between checks for new copyable files
   public static final int SLEEP_TIME = 2000;

   //copyable files are copied to numbered files
   //in numbered subdirectories:

   //the number of copied files to put in each new subdirectory
   public static final int NUM_FILES_PER_SUBDIRECTORY = 200;

   //the prefix to prepend to file copies
   //and to new subdirectories
   public static final String COPY_PREFIX = "sec";

   //the suffix to attach to file copies
   public static final String COPY_SUFFIX = ".jpg";

   //copyable files are .htm files bigger than 8K
   //modifed in the last minute:

   //time (in milliseconds) to watch copyable files
   //before assuming that
   //they have stopped changing
   public static final int DELAY_TIME = 6000;

   //file suffix of copyable files
   //(made uppercase to make it case independent)
   public static final String SUFFIX = "HTM";

   //minimum copyable file size
   public static final long MIN_FILE_SIZE = 8000;

   public static void main(String[] commandLineArguments)
      throws IllegalArgumentException
      {
      FileSaver fileSaver = new FileSaver(commandLineArguments);
      fileSaver.start();
      }

   public FileSaver(String[] arguments)
      throws IllegalArgumentException
      {
      /*
      Initialize a new FileSaver object.
      */

      //check and set the source and destination directories
      checkDirectories(arguments);

      //initialize the counters
      subDirectoryNumber = -1;
      fileNumber = -1;
      lastModifiedTime = -1;

      //create a table to record the files already copied
      filesCopiedTable = new Hashtable();
      }

   public void start()
      {
      /*
      Start a new thread.
      */

      stop = false;
      thread = new Thread(this);
      thread.start();
      }

   public void stop()
      {
      /*
      Stop the thread.
      */

      stop = true;
      thread = null;
      }

   public void run()
      {
      /*
      Copy all relevant files until told to stop.
      */

      while (!stop)
         {
         try
            {
            copyFiles(sourceDirectory, destinationDirectory);
            Thread.currentThread().sleep(SLEEP_TIME);
            }
         catch(IOException ignored)
            {
            System.out.println("Warning: IOException detected");
            }
         catch(InterruptedException ignored)
            {
            System.out.println("Warning: " +
               InterruptedException detected");
            }
         }
      }

   private void checkDirectories(String[] arguments)
      throws IllegalArgumentException
      {
      /*
      Check that the given directories
      are legal for reading and writing.

      sourceDirectory and destinationDirectory are globals.

      Throw an IllegalArgumentException
      if there's any problem with the given directories.
      */

      if (arguments.length != 2)
         throw new IllegalArgumentException("Usage: " +
            "sourceDirectory destinationDirectory");

      //create file objects for the two directories
      sourceDirectory = new File(arguments[0]);
      destinationDirectory = new File(arguments[1]);

      //check the directories
      if (! sourceDirectory.isDirectory() ||
         ! sourceDirectory.canRead())
         throw new IllegalArgumentException(
            "Problem opening directory " +
            sourceDirectory);

      if (! destinationDirectory.isDirectory() ||
         ! destinationDirectory.canWrite())
         throw new IllegalArgumentException(
            "Problem opening directory " +
            destinationDirectory);
      }

   private void copyFiles(File sourceDirectory,
      File destinationDirectory)
      throws IOException
      {
      /*
      Copy all files in sourceDirectory
      that match the filter criteria
      to destinationDirectory.

      lastModifiedTime is global.

      Throw an IOException
      if there's any problem with the given directories.
      */

      //get the sourceDirectory files
      //that match the filter criteria
      File[] files = filterFiles(sourceDirectory);

      //if there are no such files,
      //there's nothing to do, so just return
      if (files.length == 0)
         return;

      //remember the modification time
      //of the most recently modified file
      //in the source directory
      lastModifiedTime =
         getLastModifiedTime(files, lastModifiedTime);

      //copy all the matching files in the source directory
      //into the destination directory
      for (int i = 0; i < files.length; i++)
         {
         if (files[i].canRead())
            copy(files[i]);
         else
            System.out.println("Warning: unable to read a copyable file");
         }
      }

   private File[] filterFiles(File sourceDirectory)
      {
      /*
      Capture all sourceDirectory files matching the filter criteria.

      lastModifedTime is global.
      */

      //get a list of all files in the source directory
      String[] allFileNames = sourceDirectory.list();

      //filter the files
      Vector filteredFiles = new Vector();
      for (int i = 0; i < allFileNames.length; i++)
         {
         File file = new File(sourceDirectory, allFileNames[i]);

         if (file.isFile() && file.canRead() &&
            file.getName().toUpperCase().endsWith(SUFFIX) &&
            (file.lastModified() > lastModifiedTime - DELAY_TIME) &&
            (file.length() > MIN_FILE_SIZE))
            filteredFiles.addElement(file);
         }

      //put the filtered files in an array for more convenient access later
      File[] files = new File[filteredFiles.size()];
      for (int i = 0; i < filteredFiles.size(); i++)
         files[i] = (File) filteredFiles.elementAt(i);

      return files;
      }

   private long getLastModifiedTime(File[] files,
      final long lastModifiedTime)
      {
      /*
      Find the modification time of the most recently modifed file
      in an array of files.
      */

      long lastModificationTime = lastModifiedTime;
      for (int i = 0; i < files.length; i++)
         if (lastModificationTime < files[i].lastModified())
            lastModificationTime = files[i].lastModified();

      return lastModificationTime;
      }

   private void copy(File fromFile)
      throws IOException
      {
      /*
      Copy file fromFile. If it has been copied before, only copy it again
      if it has changed since then.

      filesCopiedTable is global.

      Throw an IOException if there's any problem copying the file.
      */

      //the current destination filename
      File toFile;

      //has fromFile been copied before?
      if (filesCopiedTable.containsKey(fromFile))
         {
         //get its previous destination file name
         toFile = (File) filesCopiedTable.get(fromFile);

         //return if fromFile has not been modified since it was last copied
         if ((fromFile.lastModified() <= toFile.lastModified()) &&
            (fromFile.length() == toFile.length()))
            return;
         }
      else
         {
         //fromFile is new; name its destination file
         toFile = nameNextCopy();

         //remove any nonexistant files still in the table
         cleanTable(filesCopiedTable);

         //remember the two new filenames in the hashtable
         filesCopiedTable.put(fromFile, toFile);
         }

      //copy fromFile to toFile, overwriting toFile if it already exists
      Copy.copyFile(fromFile, toFile);
      }

   private File nameNextCopy()
      {
      /*
      Decide what to name the next copy and where to place it
      and return the new filename.

      fileNumber, subDirectoryNumber, destinationDirectory, and
      destinationSubDirectory are all global.
      */

      //increment the files created counter
      fileNumber++;

      //create a new destination subdirectory every now and then
      if ((fileNumber % NUM_FILES_PER_SUBDIRECTORY) == 0)
         {
         //increment the subdirectories created counter
         subDirectoryNumber++;

         //name and create the new destination subdirectory
         String newDirectoryName = COPY_PREFIX + convertDateToString();
         destinationSubDirectory =
            new File(destinationDirectory, newDirectoryName);
         destinationSubDirectory.mkdir();
         }

      //name the new destination file
      String newFilename = COPY_PREFIX + convertDateToString() + COPY_SUFFIX;

      //return the new filename
      return new File(destinationSubDirectory, newFilename);
      }

   private String convertDateToString()
      {
      /*
      Return a String concatenation of leading-zeros versions of the current
      date and time in Indiana.
      */

      TimeZone indianaTimeZone = TimeZone.getTimeZone("IET");
      GregorianCalendar now = new GregorianCalendar(indianaTimeZone);
      String year = "" + now.get(Calendar.YEAR);
      String month =
         StringTools.convertIntToString(2, now.get(Calendar.MONTH) + 1);
      String day =
         StringTools.convertIntToString(2, now.get(Calendar.DAY_OF_MONTH));
      String hour =
         StringTools.convertIntToString(2, now.get(Calendar.HOUR_OF_DAY));
      String minute =
         StringTools.convertIntToString(2, now.get(Calendar.MINUTE));
      String second =
         StringTools.convertIntToString(2, now.get(Calendar.SECOND));
      String millisecond =
         StringTools.convertIntToString(2, now.get(Calendar.MILLISECOND));
      String date = year + month + day + hour + minute + second + millisecond;

      return date;
      }

   private void cleanTable(Hashtable table)
      {
      /*
      Remove any old files in the hashtable table that have since vanished.
      */

      Enumeration list = table.keys();
      while (list.hasMoreElements())
         {
         File file = (File) list.nextElement();

         if (!file.exists())
            table.remove(file);
         }
      }
   }


last | | contents | | next