How to catch an IOException in Unity?

Hi

Im trying to create folder, and i created a file on purpose, with the same name as the folder im trying to create. This should throw an IOException “The directory specified by path is a file.” as per docs here.

The code im using to test this is this:

        DirectoryInfo dirInf = new DirectoryInfo(myFolder);
        if(!dirInf.Exists) {
            // first try
            try {
                dirInf.Create();
            }
            catch (Exception e) {
                Debug.Log("Exception: "+e);
            }
            // second try
            try {
                dirInf.Create();
            }
            catch (IOException) {
                Debug.Log("IOException");
            }
        }

But it doesn’t log anything. The folder is not created, why am i not getting the error?

ty

Try putting a Debug.Log call at the top to ensure that the code is actually running (and that it’s able to write to the log). I also suggest you put another Debug.Log in an “else” clause so you can detect if dirInf.Exists returns true, just to be safe.

2 Likes

You say you’re creating a folder and then a file, but that’s not what your code says.

Your code is calling Create on a DirectoryInfo object twice. According to the docs:

1 Like

I didnt mention this, but i’ve done those already during the tests.

code is running, as i can clearly see the folder being created, if i remove the file.

debug is printing okay in other parts of the app (sorry im currently at stage with many errors and can’t test in the target class, but im pretty sure, this is not an issue)

all right, i must have been unclear, so let me rephrase

first, i’ve manually created the file in the target directory, to cause/test for IOException, when (second) i call the code. There is a specific case when IOException occurs, if there is a file already with the same name as the directory i want to create. The bottom line why im doing this, is that i want to ‘emulate’ the situation, so i’ve created the file manually using windows explorer and new text file, removed the extension.

to the other point, im calling CreateDirectory twice, because i was not sure im trying to catch the right Exception. As you see, i am testing for both Error and IOError, as i was not sure which one i need to test for. In any case, none of them is catched. Also, you say “If the directory already exists, this method does nothing.” - which doesnt apply in my case. Directory does not exist in my case. Im testing for Error where a file with same name already exists. Thats the IOError im testing for.

Basically, i’m trying to test for IOError catching in unity. So far i had no luck.

Sorry, I didn’t mean to pre-empt Antistone’s answer. I was just adding something additional in case you made a mistake. I see that I simply misunderstood.

You should do as @Antistone suggested and verify your code is called. You could also paste more of the context and someone may notice something wrong.

Your code logs nothing because the exception is thrown outside try {} clause. To catch an exception, you need to wrap all code, like this

try {
    DirectoryInfo dirInf = new DirectoryInfo(myFolder);
    // rest of code here
}
catch (IOException ioex) {
    Debug.Log($"{Time.frameCount}. exception: {ioex.Message}");
}
1 Like

Also please post exceptions with callstacks, not just messages, it contains a lot of useful info

Really appreciate the help. No bueno yet. I might want to create a test project just for this…

To recap: This is the updated code:

public void CreateDirectoryTest ()
    {
        Debug.Log("CreateDirectoryTest");
        string myDirectory = Application.persistentDataPath + "/" + "MyDirectory" + "/";
        try {
            DirectoryInfo dirInf = new DirectoryInfo(myDirectory);
            Debug.Log("dirInf.Exists="+dirInf.Exists);
            if(!dirInf.Exists) {
                dirInf.Create();
            }
        }
        catch (IOException ioex) {
            Debug.Log($"{Time.frameCount}. exception: {ioex.Message}");
        }
    }

This is the output (in both cases (A) and (B) [see below]):

CreateDirectoryTest
dirInf.Exists=False

Setup:
A) with no “MyDirectory” file inside target directory: “MyDirectory” folder is created. No exception (expected)
B) with “MyDirectory” file inside target directory: “MyDirectory” folder is not created. No exception (unexpected)
As you can see, the code runs (printouts)
Only other thing i can think of atm is, that somewhere in Unity there is a flag to ignore the exceptions, which i have checked or something. I would post stacktrace of the exception, but there is no exception…

It is not very obvious bu I believe I know why. In .NET the directory create method creates directory if it is not exists. This is stated in docs. You do not need to check if dir exists before creating it. Internally, Directory.Create probably calls Path.Exists to check this. Path.Exists do not cares if it is file or directory. It returns true when file is there because, well, path exists. Therefore, Directory.Create does nothing. It’s just my guess, though

But It doesn’t. It returns False. Its in my previous message.

I don’t think that’s true. You can create a DirectoryInfo object with the same path as a filename. You can even query certain properties of the file through the DI object without raising an Exception. However, Create should definitely be throwing an IOException.

@_watcher , this is pretty mysterious to me. Based on what you say is getting written to the logs, I don’t see any reason you shouldn’t be catching the IOException. Let us know what version of Unity you are using. A simple repro might be the next thing.

1 Like

@eisenpony All the above was running 2019.2.0f1.

Made a clean test project in 2019.2.0b10 just now.

Created new GameObject, dropped this script on top:

using UnityEngine;
using System.IO;

public class IOExceptionTest : MonoBehaviour
{
    void Start()
    {
        CreateDirectoryTest ();
    }

    public void CreateDirectoryTest ()
    {
        Debug.Log("CreateDirectoryTest");
        string myDirectory = Application.persistentDataPath + "/" + "MyDirectory" + "/";
        try {
            DirectoryInfo dirInf = new DirectoryInfo(myDirectory);
            Debug.Log("dirInf.Exists="+dirInf.Exists);
            if(!dirInf.Exists) {
                dirInf.Create();
            }
        }
        catch (IOException ioex) {
            Debug.Log($"{Time.frameCount}. exception: {ioex.Message}");
        }
    }
}

Same printouts as before (no exception).

Folder is created correctly, when file with same name is not present. The path i’m using is “%USERNAME%\AppData\LocalLow\UnityTests\FileSystemTests” (which depends on the company name and product name you set in PlayerSettings). Manually created a file there named “MyDirectory”.

Would any of you folks be willing to check on your machine? Might be something with my system or firewall… i have no idea.

I won’t have a chance to try for quite some time, but maybe someone else will step in. I think you tried this before, but in the meantime, you could try catching the more generic Exception, just in case something else is getting thrown, like an UnauthorizedAccessException

Replace

catch (IOException ioex) {

with

catch (Exception ioex) {
1 Like

Correct, i’ve tried that also.
Thank you anyways, im apprecciative of all the feedback received.

That seems unlikely to me; I’m not sure it’s even possible to do something like that in C#. But if you wanted to test it, you could create a simple C# console application outside Unity that runs the same test and see what happens there.

Going down the list of low-probability explanations…

Is there anything notable about the folder that could cause its creation to fail for some other reason? Does the folder’s name include unusual characters, or is it very long? Is the location where you’re doing this write-protected, encrypted, or some kind of system-related folder? What happens if you try to create the folder by hand through your operating system’s regular user interface?

1 Like

Thanks again, but i think i found out what’s going on…

I’ve tested it on Android.
What did not throw an IOException was the same approach i used in the above tests:
1A) Create MyDirectory file.
2A) Attempt to Create MyDirectory folder (didnt throw exception even on Android, but did not create the folder either).

What did throw exception, and this was an UnauthorizedAccessException, which i was then able to catch, was following:
1B) Create MyDirectory folder.
2B) Attempt to Create MyDirectory file.

Now since the docs on Directory.CreateDirectory explicitly state, that IOException should be thrown when “The directory specified by path is a file.” (and i tested that function too, and would assume DirectoryInfo is just a wrapper), then i assume a bug. Or… i misunderstood the docs in some way, and the approach i used in (1) should not throw an exception (which is weird if you ask me).

Bottom line i wanted to test catching Exceptions, and now it works at least in some case, so i can proceed further. Also, it works exactly the same way on both Android and Windows, which is good (my machine was not the problem).

Thank you for help!

1 Like

Nice investigative work. I do think it’s a bug, I can make a console app (MS compiler, .net framework 472) behave the way you expect without issue.

Even if we accept the exceptions to be different, I think it’s a problem that the method can not create the directory and not give feedback.

1 Like

You used Directory.Exists, but I meant their internal path check. I think you should try to add / character at the end so it cant mess a file with a directory anymore, I mean use this

"c:\somedir\anotherdir\mynewdirname"

instead of

“c:\somedir\anotherdir\mynewdirname”

2 Likes

I see now, i misunderstood you. This is worth investigating on my side.

EDIT: but if you check the above code, it does use forward slash at the end?

string myDirectory = Application.persistentDataPath + "/" + "MyDirectory" + "/";

I can try removing it…