Please send questions to st10@humboldt.edu .
/**
/	SLIGHTLY modified from original Lecture 10 version...
/
/   modified from "Java Examples in a Nutshell", FIRST EDITION,
/   Flanagan, O'Reilly
/   pp. 157-159
/   (LOOKS like it is the same as FileCopy in SECOND EDITION, pp. 50-51)
/   
/   a strangeness: this does not always work properly under CygWin 1.0;
/   the BufferedReader doesn't handle terminal I/O when asking if an
/   existing file should be overwritten. It does work under DOS prompt
/   and sorrel, however! (???)
/
/   modified by: Sharon M. Tuttle
/   last modified: 4-9-01 
**/

import java.io.*;

/** 
 * "This class is a standalone program to copy a file, and also
 *  defines a static copy() method that other programs can use
 *  to copy files."
 **/

public class FileCopy
{
	// "The main() method of the standalone program. Calls copy()." 
	public static void main(String args[])
	{
		// "Check arguments"
		if (args.length != 2)
		{
			System.err.println("Usage: java FileCopy " +
				" ");
			System.exit(0);
		}

		// "Call copy() to do the copy, and display any error
		//  messages it throws"
		try
		{
			copy(args[0], args[1]);
		}
		catch (IOException exc)
		{
			System.err.println(exc.getMessage());
		}
	}

	/**
	 * "The static method that actually performs the file copy.
	 *  Before copying the file, however, it performs a lot of
	 *  tests to make sure everything is as it should be."
	 */
	// note, again, the "throws" clause here;
	public static void copy(String fromName, String toName) throws IOException
	{
		File	fromFile, toFile;
		
		// "get File objects from Strings"
		fromFile = new File(fromName);
		toFile = new File(toName);

		// "First make sure the source file exists, is a file,
		//  and is readable"
		if (!fromFile.exists())
		{
			throw new IOException(
				"FileCopy: no such source file: " + fromName);
		}
		if (!fromFile.isFile())
		{
			throw new IOException(
				"FileCopy: can't copy directory: " + fromName);
		}
		if (!fromFile.canRead())
		{
			throw new IOException(
				"FileCopy: source file is unreadable: " + fromName);
		}

		// "If the destination is a directory, use the source
		//  file name as the destination file name"
		if (toFile.isDirectory())
		{
			toFile = new File(toFile, fromFile.getName());
		}

		// "If the destination exists, make sure it is a writeable
		//  file and ask before overwriting it. If the destination
		//  doesn't exist, make sure the directory exists and is
		//  writeable"
		if (toFile.exists())
		{
			if (!toFile.canWrite())
			{
				throw new IOException(
					"FileCopy: destination file is unwriteable: " +
					toName);
			}
			
			// "Ask whether to overwrite it"
			System.out.print("Overwrite existing file "  + toFile.getName()
				+ "? (y/n): ");
			System.out.flush();  // flush the System.out buffer...

			// "Get the user's response"
			// (BufferedReader example!)
			//		p. 157: "how to read lines of text with a
			//		BufferedReader that reads individual characters
			//		from an InputStreamReader, which in turn reads 
			//		bytes from System.in (an InputStream), which
			//		itself reads ketstrokes from the user's keyboard"
			BufferedReader in = new BufferedReader(
					new InputStreamReader(System.in));
		
			// readLine() then returns a string, representing
			// an entire line, from BufferedReader in;
			String response = in.readLine(); 

			// remove comment below to see the response read-in
			// by the program;
			//System.out.println("response: " + response);

			// "Check the response. If not a Yes, abort the copy."
			if (!response.equals("y") && !response.equals("Y"))
			{
				throw new IOException(
					"FileCopy: existing file was not overwritten");
			}
		
		}

		else
		{			
			// "If the file doesn't exist, check if directory exists
			//  and is writeable. If getParent() returns null, then
			//  the directory is the current directory so look up the
			//  user.dir system property to find out what that is."	
			
			// "Get the destination directory"
			// (with regard to how the file name was written ---
			// was it in a path or not?)
			String parent = toFile.getParent();

			// ...or current working directory"
			if (parent == null)
			{
				parent = System.getProperty("user.dir");
			}

			// "Convert it to a file"
			File dir = new File(parent);
		
			if (!dir.exists())
			{
				throw new IOException(
					"FileCopy: destination directory does't exist: " 
					+ parent);
			}		
			if (dir.isFile())
			{
				throw new IOException(
					"FileCopy: destionation is not a directory: " 
					+ parent);
			}
			if (!dir.canWrite())
			{
				throw new IOException(
					"FileCopy: destination directory is unwriteable: " 
					+ parent);
			}
		}

		// whew!
		// "If we've gotten this far, then everything is okay.
		//  So we copy the file, a buffer of bytes at a time."

		// "Stream to read from source"
		FileInputStream from = null;

		// "Stream to write to destination"
		FileOutputStream to = null;
							
		try
		{
			// "Create input stream"
			from = new FileInputStream(fromFile);

			// "Create output stream"
			to = new FileOutputStream(toFile);
	
			// "A buffer to hold file contents"
			byte[] buffer = new byte[4096];
		
			// "How many bytes in buffer"
			int	bytesRead;

			// "Read a chunk of bytes into the buffer, then write
			//  them out, looping until we reach the end of file
			//  (when read() returns -1). Note the combination 
			//  of assignment and comparison in this while loop.
			//  This is a common I/O programming idiom."

			// "Read bytes until EOF"
			while ((bytesRead = from.read(buffer)) != -1)
			{
				// "write bytes"
				to.write(buffer, 0, bytesRead);
			}
		}

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