Wednesday FAQs: Sub-Folder and File Access

FAQ Icon
Share on Facebook0Share on Google+1Tweet about this on TwitterShare on LinkedIn1

FAQ IconIt’s Wednesday and time for another set of frequently asked questions (FAQs). Here are some FAQs about accessing sub-folders and files.

1. How do you create a new sub-folder within the Documents or Temporary directory?

Sub-folders can be added to directories using the Lua File System (LFS). The Resource directory is read-only and cannot be modified.

Here is how you can create an Images folder in the Documents directory.

local lfs = require "lfs"

-- get raw path to app's Documents directory
local docs_path = system.pathForFile( "", system.DocumentsDirectory )

-- change current working directory
local success = lfs.chdir( docs_path ) -- returns true on success
local new_folder_path
local dname = "Images"
if success then
    lfs.mkdir( dname )
    new_folder_path = lfs.currentdir() .. "/" .. dname

You can find more information about LFS here.

2. How do you access (read or write) a file that has been placed in a sub-folder?

You can access files in a sub-folder in two ways depending on what you want to do with the file. If you want to display an image or play a sound from the file, you concatenate the sub-folder name with the file name and then supply the base directory. For example, if you want to display the cat.png file in the Images sub-folder in the Documents directory, do the following:

local catImage = display.newImage( "Images/cat.png", system.DocumentsDirectory, 0, 0 )

Note that you don’t use system.pathForFile in API calls that require a baseDirectory parameter (e.g., display.newImage, display.newImageRect, audio.loadSound, etc.).

If you want to open the readme.txt file in that same directory, do the following using system.pathForFile:

local path = system.pathForFile( "Images/readme.txt", system.DocumentsDirectory )
local fileHandle = path )
-- You can now use fileHandle:read or fileHandle:write to read or write the file.

The fileHandle will not be nil if the file exists, which leads into our next question.

3. How do you test that a file exists in a folder or sub-folder?

The following function can be called from your code to see if a file exists in a folder or sub-folder. Just remember to append the sub-folder name to the file name before calling this function.

-- doesFileExist
-- Checks to see if a file exists in the path.
-- Enter:   name = file name
--  path = path to file (directory)
--  defaults to ResourceDirectory if "path" is missing.
-- Returns: true = file exists, false = file not found
function doesFileExist( fname, path )

    local results = false

    local filePath = system.pathForFile( fname, path )

    -- filePath will be nil if file doesn't exist and the path is ResourceDirectory
    if filePath then
        filePath = filePath, "r" )

    if  filePath then
        print( "File found -> " .. fname )
        -- Clean up our file handles
        results = true
        print( "File does not exist -> " .. fname )


    return results

Here’s how the above function is called.

-- Checking for file in Documents directory
local results = doesFileExist( "Images/cat.png", system.DocumentsDirectory )
-- or checking in Resource directory
local results = doesFileExist( "Images/cat.png" )

4. How do you copy a file to a sub-folder?

The following function allows copying a file from one folder to another. One common use is to copy a file shipped in the Resource directory to the Documents directory. You must create any sub-folders (if they don’t exist) before using this function.

-- copyFile( src_name, src_path, dst_name, dst_path, overwrite )
-- Copies the source name/path to destination name/path
-- Enter:   src_name = source file name
--      src_path = source path to file (directory), nil for ResourceDirectory
--      dst_name = destination file name
--      overwrite = true to overwrite file, false to not overwrite
-- Returns: false = error creating/copying file
--      nil = source file not found
--      1 = file already exists (not copied)
--      2 = file copied successfully
function copyFile( srcName, srcPath, dstName, dstPath, overwrite )

    local results = false

    local srcPath = doesFileExist( srcName, srcPath )

    if srcPath == false then
        -- Source file doesn't exist
        return nil

    -- Check to see if destination file already exists
    if not overwrite then
        if fileLib.doesFileExist( dstName, dstPath ) then
            -- Don't overwrite the file
            return 1

    -- Copy the source file to the destination file
    local rfilePath = system.pathForFile( srcName, srcPath )
    local wfilePath = system.pathForFile( dstName, dstPath )

    local rfh = rfilePath, "rb" )

    local wfh = wfilePath, "wb" )

    if  not wfh then
        print( "writeFileName open error!" )
        return false            -- error
        -- Read the file from the Resource directory and write it to the destination directory
        local data = rfh:read( "*a" )
        if not data then
            print( "read error!" )
            return false    -- error
            if not wfh:write( data ) then
                print( "write error!" )
                return false    -- error

    results = 2     -- file copied

    -- Clean up our file handles

    return results

Here is how to use the copy file routine to copy the readme.txt file from the Resource to the Documents directory.

copyFile( "readme.txt", nil, "readme.txt", system.DocumentsDirectory, true )
local catImage = display.newImage( "cat.png", system.DocumentsDirectory, 0, 0 )

5. What are the Android restrictions concerning files?

File access in Corona is based on the underlining Operating System, which will vary depending on the platform. On iOS devices, you can access files in the Resource directory (where main.lua is located) and the Documents and Temporary directories. On Android, accessing the Resource directory is limited because it’s not a real directory, but files are enclosed in a zip file. Corona allows directly loading images and audio files using audio and image APIs, but has limited access to Resource files using the file I/O APIs.

Because of this limitation on Android, if you have files shipped in the Resource directory that you want to copy to another directory (e.g., Documents), you will need to change the file name in the resource directory so it can be access by the file I/O APIs. For example, if you want to move an image file from the Resource to the documents directory, it must be renamed with a different extension so it can be accessed. Our cat.png file would need to be called cat.png.txt so it could be copied.

Here is how you would copy the cat.png file to the Documents directory on Android (assuming it was stored as cat.png.txt).

copyFile( "cat.png.txt", nil, "cat.png", system.DocumentsDirectory, true )
local catImage = display.newImage( "cat.png", system.DocumentsDirectory, 0, 100 )

The file extensions that cannot be read in the Resource directory by Android are: html, htm, 3gp, m4v, mp4, png, jpg, and rtf.

The above technique works for all platforms so if you make it work for Android, it will work everywhere.

That’s it for today’s FAQs. I hope you enjoyed them and even learned a few things.

Share on Facebook0Share on Google+1Tweet about this on TwitterShare on LinkedIn1

This entry has 4 replies

  1. Jose says:

    Good post Tom! Got here from my question on the forum about the pathForFile warnings (, but I’m afraid I have the same problem with your code.
    Is there any other way to get the existence of a file skipping the warnings pathForFile causes when it doesn’t find the file???
    Anyway, the points 1 & 4 are of great help for my next projects, thanks!

  2. Alberto says:


    Concerning Android devices, is it possible to create sub-folders and copy files to external storage?

    My Android device has got 2Gb of internal storage and 16Gb of nand flash storage.
    The app I’m developing let user downloads catalogs about 1Gb size, so I need to use the 16Gb from flash storage.
    Is it possible?

    Thanks in advance!


  3. Alberto says:

    Just another issue:
    I’ve created a sub directory in system.DocumentsDirectory and I want to download files directly into that sub-folder I created. When i try and feed it a path other than system base directories, it ignors them and reverts to the default of system.DocumentsDirectory, in spite of adding the subdirectory name.

    Is not possible to directly download to the sub-foldr I’ve just created?


  4. lessmsios says:

    In the copy function the line:

    local srcPath = doesFileExist( srcName, srcPath )

    will over write the parameter srcPath. If you use this function as is without renaming that test it will throw an error.

Leave a reply

You may use these HTML tags and attributes: <a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>