Problems reading json files from system.ResourceDirectory

Hello Everyone,

I am having some troubles opening json files read that are located in the ResourceDirectory.

When calling the system.pathForFile passing the file name and directory it returns what it seems a valid path but passing the returned filePath to io.open(filePath, “r”) it returns a “No such file or directory error”.

Following the same procedure using the documents directory seems to work fine. Is there any special behavior about reading the ResourceDirectory ? If the file was indeed missing would it return a nil path (as it happens on the other platforms) ? Am I missing something here ?

This is happening because your JSON file is not be bundled into your app.  Visual Studio does not automatically include files as “content” for extensions it does not recognize, such as JSON files.

What you need to do is the following:

  1. Go to the Solution Explorer panel in Visual Studio.

  2. Right click on your JSON file and select Properties from the popup menu.

  3. In the Properties panel, go to the “Build Action” property and select “Content”.

I recommend that you go through all of your asset files to ensure that they’re Build Action is set to Content.

(This isn’t a Corona thing.  This is something all Visual Studio developers need to be aware of.)

Note that we document this in the link below.  See topic “How to add an existing Corona project to this Visual Studio project”.

   http://docs.coronalabs.com/daily/coronacards/wp8/index.html#create-a-coronacards-app

Oh, sorry missed that last step, to set it to content. I managed to read the file after setting it.

Just one more question. Will the system.pathForFile always return a valid path for me then ? So the only way to check if a file exists is opening it in read mode ?

Happy to help!

>> Will the system.pathForFile always return a valid path for me then ?

If system.pathForFile() fails to find the file, then it is *supposed* to return nil.

I verified it works this way in the Corona Simulator… but it’s returning a path to the non-existing file on WP8.  That’s not the correct behavior.  Thanks for finding this issue.  I’ll correct it later.

Hmm… after digging into this, I’ve discovered that we do not handle this consistently between platforms.

I did discover that we have an undocumented feature where you can provide a 3rd argument to this function to test whether or not to check for file existence.  You set the 3rd argument to “true” to force it to check for file existence, in which case it’ll return nil if not found.  By default it is false, but unfortunately it looks like the Windows Corona Simulator and Android check for existence anyways if it is a ResourceDirectory file.

   system.pathForFile(“MyFile.txt”, system.DocumentsDirectory, true)

In the Windows and Mac versions of the Corona Simulator, it always checks for file existence for files in the ResourceDirectory (cannot be turned off), but it does *not* check for file existence by default for any other directory.  I’m going to modify WP8 to match this behavior.

That was a good find.  I learned something new about our own Corona API that I didn’t even know about.

Huh… that may explain some weird behaviors we were seeing on Android devices.

We were implementing some features that required us to check if a file existed in the ResourceDirectory and then chose the correcting one depending on the ones present. It worked fine on all simulators and iOS devices, but on Android devices it failed.

We did some tests and found out that the first time we called system.pathForFile on an unexisting file, it return a null path and our feature worked fine, but if we called pathForFile a second time on the same file, it returned a valid path. Turns out, Android was creating an empty “local” file after the first call to pathForFile.

We assumed it was a problem with how Android handles reading files that are located in the apk instead of the local storage, but it may be that this extra feature is doing something extra that causes the Android OS to create the file.

On Android, we have implemented a *hack* where system.pathForFile() will extract the specified file (depending on its extension) from the APK (which is really a zip file) and dump it into a temporary directory.  This makes the file reachable via Lua’s io.* file APIs.  But that said, if the file doesn’t exist in the APK, we should be created an empty file anyways… if in fact that’s the behavior you’re seeing.

This is happening because your JSON file is not be bundled into your app.  Visual Studio does not automatically include files as “content” for extensions it does not recognize, such as JSON files.

What you need to do is the following:

  1. Go to the Solution Explorer panel in Visual Studio.

  2. Right click on your JSON file and select Properties from the popup menu.

  3. In the Properties panel, go to the “Build Action” property and select “Content”.

I recommend that you go through all of your asset files to ensure that they’re Build Action is set to Content.

(This isn’t a Corona thing.  This is something all Visual Studio developers need to be aware of.)

Note that we document this in the link below.  See topic “How to add an existing Corona project to this Visual Studio project”.

   http://docs.coronalabs.com/daily/coronacards/wp8/index.html#create-a-coronacards-app

Oh, sorry missed that last step, to set it to content. I managed to read the file after setting it.

Just one more question. Will the system.pathForFile always return a valid path for me then ? So the only way to check if a file exists is opening it in read mode ?

Happy to help!

>> Will the system.pathForFile always return a valid path for me then ?

If system.pathForFile() fails to find the file, then it is *supposed* to return nil.

I verified it works this way in the Corona Simulator… but it’s returning a path to the non-existing file on WP8.  That’s not the correct behavior.  Thanks for finding this issue.  I’ll correct it later.

Hmm… after digging into this, I’ve discovered that we do not handle this consistently between platforms.

I did discover that we have an undocumented feature where you can provide a 3rd argument to this function to test whether or not to check for file existence.  You set the 3rd argument to “true” to force it to check for file existence, in which case it’ll return nil if not found.  By default it is false, but unfortunately it looks like the Windows Corona Simulator and Android check for existence anyways if it is a ResourceDirectory file.

   system.pathForFile(“MyFile.txt”, system.DocumentsDirectory, true)

In the Windows and Mac versions of the Corona Simulator, it always checks for file existence for files in the ResourceDirectory (cannot be turned off), but it does *not* check for file existence by default for any other directory.  I’m going to modify WP8 to match this behavior.

That was a good find.  I learned something new about our own Corona API that I didn’t even know about.

Huh… that may explain some weird behaviors we were seeing on Android devices.

We were implementing some features that required us to check if a file existed in the ResourceDirectory and then chose the correcting one depending on the ones present. It worked fine on all simulators and iOS devices, but on Android devices it failed.

We did some tests and found out that the first time we called system.pathForFile on an unexisting file, it return a null path and our feature worked fine, but if we called pathForFile a second time on the same file, it returned a valid path. Turns out, Android was creating an empty “local” file after the first call to pathForFile.

We assumed it was a problem with how Android handles reading files that are located in the apk instead of the local storage, but it may be that this extra feature is doing something extra that causes the Android OS to create the file.

On Android, we have implemented a *hack* where system.pathForFile() will extract the specified file (depending on its extension) from the APK (which is really a zip file) and dump it into a temporary directory.  This makes the file reachable via Lua’s io.* file APIs.  But that said, if the file doesn’t exist in the APK, we should be created an empty file anyways… if in fact that’s the behavior you’re seeing.