SE251Ex:File

From Marks Wiki
Jump to navigation Jump to search

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