Search Unity

How to catch an IOException in Unity?

Discussion in 'Scripting' started by _watcher_, Nov 20, 2019.

  1. _watcher_

    _watcher_

    Joined:
    Nov 7, 2014
    Posts:
    261
    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:
    Code (CSharp):
    1.         DirectoryInfo dirInf = new DirectoryInfo(myFolder);
    2.         if(!dirInf.Exists) {
    3.             // first try
    4.             try {
    5.                 dirInf.Create();
    6.             }
    7.             catch (Exception e) {
    8.                 Debug.Log("Exception: "+e);
    9.             }
    10.             // second try
    11.             try {
    12.                 dirInf.Create();
    13.             }
    14.             catch (IOException) {
    15.                 Debug.Log("IOException");
    16.             }
    17.         }
    But it doesn't log anything. The folder is not created, why am i not getting the error?

    ty
     
    Last edited: Nov 21, 2019
  2. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    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.
     
    _watcher_ and JeffDUnity3D like this.
  3. eisenpony

    eisenpony

    Joined:
    May 8, 2015
    Posts:
    974
    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:
     
    _watcher_ likes this.
  4. _watcher_

    _watcher_

    Joined:
    Nov 7, 2014
    Posts:
    261
    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)
     
    Last edited: Nov 21, 2019
  5. _watcher_

    _watcher_

    Joined:
    Nov 7, 2014
    Posts:
    261
    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.
     
    Last edited: Nov 21, 2019
  6. eisenpony

    eisenpony

    Joined:
    May 8, 2015
    Posts:
    974
    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.
     
  7. palex-nx

    palex-nx

    Joined:
    Jul 23, 2018
    Posts:
    1,748
    Your code logs nothing because the exception is thrown outside try {} clause. To catch an exception, you need to wrap all code, like this

    Code (CSharp):
    1. try {
    2.     DirectoryInfo dirInf = new DirectoryInfo(myFolder);
    3.     // rest of code here
    4. }
    5. catch (IOException ioex) {
    6.     Debug.Log($"{Time.frameCount}. exception: {ioex.Message}");
    7. }
    8.  
     
    _watcher_ likes this.
  8. palex-nx

    palex-nx

    Joined:
    Jul 23, 2018
    Posts:
    1,748
    Also please post exceptions with callstacks, not just messages, it contains a lot of useful info
     
  9. _watcher_

    _watcher_

    Joined:
    Nov 7, 2014
    Posts:
    261
    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:
    Code (CSharp):
    1. public void CreateDirectoryTest ()
    2.     {
    3.         Debug.Log("CreateDirectoryTest");
    4.         string myDirectory = Application.persistentDataPath + "/" + "MyDirectory" + "/";
    5.         try {
    6.             DirectoryInfo dirInf = new DirectoryInfo(myDirectory);
    7.             Debug.Log("dirInf.Exists="+dirInf.Exists);
    8.             if(!dirInf.Exists) {
    9.                 dirInf.Create();
    10.             }
    11.         }
    12.         catch (IOException ioex) {
    13.             Debug.Log($"{Time.frameCount}. exception: {ioex.Message}");
    14.         }
    15.     }
    This is the output (in both cases (A) and (B) [see below]):
    Code (CSharp):
    1. CreateDirectoryTest
    2. 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..
     
    Last edited: Nov 21, 2019
  10. palex-nx

    palex-nx

    Joined:
    Jul 23, 2018
    Posts:
    1,748
    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
     
  11. _watcher_

    _watcher_

    Joined:
    Nov 7, 2014
    Posts:
    261
    But It doesn't. It returns False. Its in my previous message.
     
  12. eisenpony

    eisenpony

    Joined:
    May 8, 2015
    Posts:
    974
    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.
     
    _watcher_ likes this.
  13. _watcher_

    _watcher_

    Joined:
    Nov 7, 2014
    Posts:
    261
    @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:
    Code (CSharp):
    1. using UnityEngine;
    2. using System.IO;
    3.  
    4. public class IOExceptionTest : MonoBehaviour
    5. {
    6.     void Start()
    7.     {
    8.         CreateDirectoryTest ();
    9.     }
    10.  
    11.     public void CreateDirectoryTest ()
    12.     {
    13.         Debug.Log("CreateDirectoryTest");
    14.         string myDirectory = Application.persistentDataPath + "/" + "MyDirectory" + "/";
    15.         try {
    16.             DirectoryInfo dirInf = new DirectoryInfo(myDirectory);
    17.             Debug.Log("dirInf.Exists="+dirInf.Exists);
    18.             if(!dirInf.Exists) {
    19.                 dirInf.Create();
    20.             }
    21.         }
    22.         catch (IOException ioex) {
    23.             Debug.Log($"{Time.frameCount}. exception: {ioex.Message}");
    24.         }
    25.     }
    26. }
    27.  
    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.
     
    Last edited: Nov 21, 2019
  14. eisenpony

    eisenpony

    Joined:
    May 8, 2015
    Posts:
    974
    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
    Code (csharp):
    1. catch (IOException ioex) {
    with
    Code (csharp):
    1. catch (Exception ioex) {
     
    _watcher_ likes this.
  15. _watcher_

    _watcher_

    Joined:
    Nov 7, 2014
    Posts:
    261
    Correct, i've tried that also.
    Thank you anyways, im apprecciative of all the feedback received.
     
  16. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    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?
     
    _watcher_ likes this.
  17. _watcher_

    _watcher_

    Joined:
    Nov 7, 2014
    Posts:
    261
    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!
     
    Last edited: Nov 21, 2019
    eisenpony likes this.
  18. eisenpony

    eisenpony

    Joined:
    May 8, 2015
    Posts:
    974
    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.
     
    _watcher_ likes this.
  19. palex-nx

    palex-nx

    Joined:
    Jul 23, 2018
    Posts:
    1,748
    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"
     
    eisenpony and _watcher_ like this.
  20. _watcher_

    _watcher_

    Joined:
    Nov 7, 2014
    Posts:
    261
    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?
    Code (CSharp):
    1. string myDirectory = Application.persistentDataPath + "/" + "MyDirectory" + "/";
    I can try removing it..
     
    Last edited: Nov 22, 2019
  21. _watcher_

    _watcher_

    Joined:
    Nov 7, 2014
    Posts:
    261
    So the console app behaves as expected, according to @eisenpony, which is great, thanks @eisenpony.
    Otherwise no, im using Application.persistentDataPath, and the name of the folder is MyDirectory. Also since file is created no problems, i don't think its a write protection issue.
     
  22. _watcher_

    _watcher_

    Joined:
    Nov 7, 2014
    Posts:
    261
    Solved!
    Thanks @palex-nx, and everyone else, for help.
    The slash was the issue. Its a bit funny, how simple that was.
    So the piece of code that changed from what's already listed above:
    Code (CSharp):
    1. string myDirectory = Application.persistentDataPath + "/" + "MyDirectory";
    :)
     
    eisenpony and palex-nx like this.
  23. palex-nx

    palex-nx

    Joined:
    Jul 23, 2018
    Posts:
    1,748
    The fun part is I was thinking adding the slash will fix the issue, but actually issue is fixed by removing the slash, lol )
     
    _watcher_ likes this.
  24. eisenpony

    eisenpony

    Joined:
    May 8, 2015
    Posts:
    974
    Nice work. I never would have caught that!
     
    _watcher_ likes this.