SE251Ex:File
Writing a simple Java shell
Description
Write a simple interactive shell-like program for browsing through the file system and manipulating files and directories. Like a typical shell (either your Linux shell or Windows command prompt) it has the concept of a working directory from which you can list, create and delete files and folders. Also it continuously prompts for user's input and performs file operations corresponding to the input until an "exit" command is issued. The operations are formatted as a '<command> <argument>' String, where <argument> is optional depending on the <command>. The following are the operations that your program supports:
Command | Argument | Description |
---|---|---|
cd | <path> | change working directory to the path <working directory>/<path>, if it exists |
ls | <path> or empty | list the names of files and folders from the path <working directory>/<path> if path is given; if empty then from the <working directory> |
mkdir | <name> | create a new directory with the pathname <working directory>/<name> and report its success. Obviously you can't create a new directory if it already exists or has an invalid name. |
newfile | <name> | create a new file with the pathname <working directory>/<name> and report its success Obviously you can't create a new file if it already exists or has an invalid name. |
rm | <name> | delete the file or directory with the pathname <working directory>/<name> and report its success. Note directories can only be deleted if they are empty. |
exit | none | terminate the program |
Below is an example of running your program under the initial working directory E:\temp:
E:\temp> ls assignment1.txt code/ docs/ graphics/ projectreport.pdf E:\temp> ls bogus Directory E:\temp\bogus doesn't exist E:\temp> ls code GoodbyeWorld.class GoodbyeWorld.java statements.html E:\temp> cd code E:\temp\code> ls GoodbyeWorld.class GoodbyeWorld.java statements.html E:\temp\code> newfile temp.txt Created temp.txt E:\temp\code> mkdir tempdir Created tempdir E:\temp\code> ls GoodbyeWorld.class GoodbyeWorld.java statements.html temp.txt tempdir/ E:\temp\code> newfile tempdir/deleteme Created deleteme E:\temp\code> newfile statements.html Couldn't create statements.html E:\temp\code> rm temp.txt Removed temp.txt E:\temp\code> rm tempdir Couldn't remove tempdir E:\temp\code> rm tempdir/deleteme Removed deleteme E:\temp\code> rm tempdir Removed tempdir E:\temp\code> ls GoodbyeWorld.class GoodbyeWorld.java statements.html E:\temp\code> exit Bye!
CAUTION!! - Assuming your program works properly, it will be modifying your file system directly. So make sure you are working under a safe "sandbox" directory where there is no worry of accidental deletion!
Below is a template code that you can use to get started with the program.
import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; public class SimpleFileShell { /** This is a special way of obtaining the default working directory */ public static final String STARTING_DIRECTORY = System.getProperty("user.dir"); /** String constants for commands */ public static final String CD = "cd"; //change directory public static final String LS = "ls"; //list files public static final String MKDIR = "mkdir"; //make directory public static final String NEWFILE = "newfile"; //new file public static final String RM = "rm"; //remove given file public static final String RM_DIR = "rmdir"; //recursively remove given directory public static final String EXIT = "exit"; //exit public void execute() { BufferedReader input = new BufferedReader(new InputStreamReader(System.in)); //currentDir keeps track of the current working directory //the command 'cd' will change this variable accordingly File currentDir = new File(STARTING_DIRECTORY); while (true) { //Keep looping until "exit" is entered try { //Note: Java has a printf method too! System.out.printf("%s> ", currentDir.getCanonicalPath()); String commandLine = input.readLine(); if (commandLine.equals(EXIT)) { System.out.println("Bye!"); break; //break out of the while loop. i.e. finish } //split the command string into tokens separated by whitespace //"[ \\t]+" is a regular expression meaning "one or many spaces //or tabs" String[] commandTokens = commandLine.split("[ \\t]+"); if (commandTokens.length == 0) { //i.e. nothing but whitespace continue; //skip to the next iteration of the loop } String command = commandTokens[0]; //get the first token: the command String arg = null; if (commandTokens.length > 1) { arg = commandTokens[1]; //get the second token: the argument to the command } currentDir = process(command, arg, currentDir); } catch (IOException e) { //System.err is a different stream to System.out, and it's generally //used for reporting errors. System.err.printf("IO error while processing input. Reason: %s\n",e.getMessage()); } } try { input.close(); } catch (IOException e) { e.printStackTrace(); } } private File process(String command, String arg, File currentDir) { File nextDir = currentDir; if (command.equals(CD) && arg != null) { //your code here } else if (command.equals(LS)) { //your code here } else if (command.equals(MKDIR) && arg != null) { //your code here } else if (command.equals(NEWFILE) && arg != null) { //your code here } else if (command.equals(RM) && arg != null) { //your code here } else { //unknown command! //your code here } return nextDir; } public static void main(String[] args) { SimpleFileShell shell = new SimpleFileShell(); shell.execute(); } }
Tips
- Make use of the File class from the java.io package.
A File object represents a file or a directory in the native file system and provides methods for creating, deleting and listing among many other things. You create a new File object usually in two ways. The first being:
File file = new File("C:/temp/myfile");
where you pass in a pathname as a string. The second being:
File parent = new File("C:/temp"); File file = new File(parent, "myfile");
where you pass in a parent directory and the file to go under it. Both of the above result in a new File object representing the pathname "C:/temp/myfile". Note that this does not physically create the file in the file system. To do this you need to explicitly call either createNewFile() or mkdir() depending on whether it is to be a file or a directory, respectively. Both methods return a boolean, where true indicates the file or directory was created successfully, and false if otherwise. What this also means is you can create a new File object for a file that already exists in the file system. You can call exists() to check if it actually exists.
If your File represents a directory, then you can call listFiles() to return all its constituent files and directories as an array of Files. Usually you would want to first check that it is indeed a directory (because otherwise listFiles() will return null), for which you call isDirectory(). To delete a file, call delete(), which again returns a boolean indicating the success. Note that directories can be deleted this way only if it is empty.
Optional Extensions
- Prompt user before deletion of a file. For example:
E:\temp\graphics> rm importantdocument.pdf Are you sure (y/n)? y Deleted.
- Introduce a new command called "rmdir" which recursively deletes a given directory, just like the Unix command "rm -rf". Recursively deleting a directory means deleting all contents of the directory first, then deleting the directory itself. Realise some of the contents may be directories themselves, hence they will further be recursively deleted in the process. The general algorithm is simple:
recursiveDelete(f) { if f is a directory { for each f' inside f { recursiveDelete(f') } } delete f }
Again, be careful where you perform this operation: make sure you are working under a sandbox directory!
- This program exhibits a problem similar to the Banking assignment - introduction of every new command will result in the bloating of the method process(). Apply object-oriented techniques to make it easier and cleaner to introduce new commands.
Discussion
Here you can ask questions and discuss stuff