File Management and XML in Unity 3D using C# - Page 2: Directories

  • File Management and XML in Unity 3D using C# - Page 2: Directories

    File Management and XML in Unity 3D using C# - Page 2: Directories

    Posted by FIZIX Richard on Fri 31st August 2012 7:22pm

    In part 2 of the file management in Unity 3D tutorial we will be learning how to add directory management functions to our fileManager class. This will show you how to check whether directories exist, how to create, delete and move directories and also how to return the contents of a directory.

    Return to page 1: Introduction and creating the file management class

    Checking Directories

    You can create directories with Unity which is useful for a number of different things. It is important whenever you create, edit or delete a file or directory to check whether it exists before you attempt to perform any operation on it. So we will create a simple method to check whether a directory exists.

    In the fileManager script, add the following method:


    // --------------------------------------------------------------------------------------------------- // checkDirectory() // --------------------------------------------------------------------------------------------------- // checks to see whether the passed directory exists, returning true of false // --------------------------------------------------------------------------------------------------- private bool checkDirectory(string directory) { if(Directory.Exists(path + "/" + directory)) { return true; } else { return false; } } // ---------------------------------------------------------------------------------------------------

    This method receives a directory name to check and uses the Directory.Exists() function to check whether or not the directory exists, if it does the method returns true else it returns false.

    Note that we are constructing the path to the directory within the Directory.Exists() function using the path variable we populated previously, appending the passed directory name. The directory that we pass to this method could be a single directory name such as "gamedata" or it would be path such as "gamedata/saves".

    Creating Directories

    Now we will look at creating a directory. We will need a "gamedata" directory within which we will store our data files, so we will check to see if the directory exists, if it does not then we shall create it.

    Add the following method to the fileManager class:


    // --------------------------------------------------------------------------------------------------- // createDirectory() // --------------------------------------------------------------------------------------------------- // creates a new directory, // --------------------------------------------------------------------------------------------------- private void createDirectory(string directory) { print ("Creating directory: " + directory); Directory.CreateDirectory(path + "/" + directory); } // ---------------------------------------------------------------------------------------------------

    This method similarly to the checkDirectory method, receives a directory name as a string and attempts to create the directory using the Directory.CreateDirectory() function.

    Now to pull this together, add the following block of code to the initialize function, below where we discovered the path:


    // Check for and create the gamedata directory if(checkDirectory("gamedata") == false) { createDirectory("gamedata"); }

    This new block of code will check whether the "gamedata" directory exists and if it doesn't will create it; using our checkDirectory and createDirectory methods. You'll know whether the directory is being created as we're outputting a message to the console in the createDirectory() method. Additionally you can refresh the project panel and you should see the gamedata directory has been created.

    In practice you will probably want to check whether the directory or file already exists before performing any operation such as create, edit or delete within the method that performs the operation. So in a live game you would check whether the directory exists within the createDirectory() method. In doing so you don't expose yourself to issues if a programmer forgets to check a directory or file before calling the management function.

    So, edit the createDirectory() method to match the code below:


    private void createDirectory(string directory) { if(checkDirectory(directory) == false) { print("Creating directory: " + directory); Directory.CreateDirectory(path + "/" + directory); } else { print("Error: You are trying to create the directory " + directory + " but it already exists!"); } }

    We have simply nested our create directory code within an if statement which checks whether the directory already exists. If the directory already exists then we output a message to the console to let the developers know that something has gone awry.

    Deleting Directories

    There may be occasions where you need to delete directories and their contents. So let's add a delete directory method to our file manager class:


    // --------------------------------------------------------------------------------------------------- // deleteDirectory() // --------------------------------------------------------------------------------------------------- // deletes a directory // --------------------------------------------------------------------------------------------------- private void deleteDirectory(string directory) { if(checkDirectory(directory) == true) { print("Deleting directory: " + directory); Directory.Delete(path + "/" + directory, true); } else { print("Error: You are trying to delete the directory " + directory + " but it does not exist!"); } } // ---------------------------------------------------------------------------------------------------

    Like our previous methods we are passing in the directory name to delete as a string, then checking whether the directory exists within an if statement. If the directory exists we are deleting the directory, else if it does not exist we are outputting an error message to the console.

    Drawing your attention to the Directory.Delete() function, you have two parameters that are being passed in:

    Parameter 1: The path to the directory to delete
    Parameter 2: A boolean flag which tells the OS whether to delete any sub directories or files within the directory.

    You can call this method by adding "deleteDirectory("directory_name_to_delete"); in your code. If you want to test the method add a call in the initialize method, but don't forget to remove the call.

    Moving Directories

    You may also wish to move a directory from one place to another, so we will create a simple move directory method:


    // --------------------------------------------------------------------------------------------------- // moveDirectory() // --------------------------------------------------------------------------------------------------- // moves a directory // --------------------------------------------------------------------------------------------------- private void moveDirectory(string originalDestination, string newDestination) { if(checkDirectory(originalDestination) == true && checkDirectory(newDestination) == false) { print("Moving directory: " + originalDestination); Directory.Move(path + "/" + originalDestination, path + "/" + newDestination); } else { print("Error: You are trying to move a directory but it either does not exist or a folder of the same name already exists"); } } // ---------------------------------------------------------------------------------------------------

    This method receives two strings, the folder that you want to move and the location you want to move it too. The method checks that the originalDestination path exists and that the newDestination path does not exist. The method then moves the directory.

    To test this:

    1. Add a folder in the project panel called "saves"
    2. Add the following code to the initialize method:


    // If there is a saves directory in the application root, move it to gamedata if(checkDirectory("saves") == true) { moveDirectory("saves", "gamedata/saves"); }

    If there is a directory called "saves" in the games application data root then we move it to the gamedata folder.

    Listing Sub Directories

    You may want to discover any sub directories within a directory. Before we do this, make sure your gamedata folder has the following sub directories:

    - saves
    - xml

    With those two directories created, we will now add a "list subdirectories" method:


    // --------------------------------------------------------------------------------------------------- // findSubDirectories() // --------------------------------------------------------------------------------------------------- // Finds subdirectories of a given directory // --------------------------------------------------------------------------------------------------- public string [] findSubDirectories(string directory) { print("Checking directory " + directory + " for sub directories"); string [] subdirectoryList = Directory.GetDirectories(path + "/" + directory); return subdirectoryList; } // ---------------------------------------------------------------------------------------------------

    This method simply returns a list of sub directories within the passed directory, as this will usually be called from another method that will have previously validated everything we aren't validating here.

    To use this method, add the following code to the initialize method:


    // Grab subdirectories in "gamedata" and list them string [] subdirectoryList = findSubDirectories("gamedata"); foreach(string subdirectory in subdirectoryList) { print ("Found: " + subdirectory); }

    If you run test the game now you will have our two sub directories "saves" and "xml" listed in the console. You may notice that the full path is returned by the Directory.GetDirectories() method, therefore depending on your games requirements you may want to strip the leading path away. The main reason for providing a full path is because you can call this function recursively in order to find all subdirectories, for example, in a military strategy game where unit data is stored in xml files, you could recursively read a deep directory structure like so:


    You can also add search patterns to the Directory.GetDirectories() function. For example if you were to modify the Directory.GetDirectories() function in the findSubDirectories() method like so:


    Directory.GetDirectories(path + "/" + directory, "x*");

    This would return directories that begin with an 'x', the * is a wildcard operator. You could adjust the findSubDirectories() method so that it accepts a second "searchTerm" parameter so that you can either return all subdirectories or only return subdirectories that match whatever search criteria you specify.

    Listing Directory Contents

    We know how to return the sub-directories within a directory, but how about the files within a directory, for this we use the GetFiles() function, so let's add a new method to handle this:


    // --------------------------------------------------------------------------------------------------- // findFiles() // --------------------------------------------------------------------------------------------------- // returns the files within a given directory // --------------------------------------------------------------------------------------------------- public string [] findFiles(string directory) { print("Checking directory " + directory + " for files"); string [] fileList = Directory.GetFiles(path + "/" + directory); return fileList; } // ---------------------------------------------------------------------------------------------------

    Then add a few test XML files to the "gamedata/xml" directory before adding the following code to the initialize() method:


    // Grab files in "gamedata" directory and list them string [] fileList = findFiles("gamedata/xml"); foreach(string file in fileList) { print ("Found File: " + file); }

    Like before, when you test the application the test xml files you added will be listed, additionally like with directory listings you can search files using wildcards by calling Directory.GetFiles() with a search pattern like so:

    Directory.GetFiles(path + "/" + directory, searchString);

    Tidying Up and Comments

    Before continuing there are a few things we need to do and some other bits to run over.

    Tidying Up
    First, cut the test method calls from the initialize() function so that the initialize() method matches the code below:


    // --------------------------------------------------------------------------------------------------- // initialize() // --------------------------------------------------------------------------------------------------- // initializes the file manager // --------------------------------------------------------------------------------------------------- public void initialize() { print("file manager initialized."); path = Application.dataPath; print("Path: " + path); // Check for and create the gamedata directory if(checkDirectory("gamedata") == false) { createDirectory("gamedata"); } } // ---------------------------------------------------------------------------------------------------

    Then remove any test xml files you added to the xml directory.

    Some important notes
    Firstly, you may notice that there are a few flaws with the methods we have added, namely that our validation is very loose. It's important to check the variables a method receives; critically in some cases, that they are not empty. For example, if an empty value was passed to the deleteDirectory method, this could cause unwanted deletion of entire directory structures.

    Also there are a great number of different directory management functions that you can use, if you check the MSDN Directory Methods Reference you will find a complete list although the implementation examples may need tweaking for use in Unity. We have however covered the important methods that are probably most common.

    Continue to page 3 where we will look at creating and managing files.