File system access

The data files that you work with in your apps are stored in the file system on the device.

Different file system locations have different permissions; in some areas, you can create new files to store your app data, while in others, you can only load data from existing files. If you want to access your data files using the method that works best for you, you need to understand where your data files are located in the file system.

Before you can do any work in the file system on the device, you should make yourself familiar with the working directory. The working directory is where your app is started and is also known as the current directory and the sandbox. Access to files and folders in the working directory is governed by UNIX-style groups and permissions.

Data files that you package with your app (when you compile the app) are located in the assets folder in the file system. Your app has read-only access to this folder, which means that you can load data from files in this location, but you can't save new data in these files. When you create new data files dynamically while your app is running, they are stored in the data folder. Your app has full read-write access to this folder, so you can load and save data using files in this location.

Applications cannot create new folders or files at the root of the working directory; they can access only the folders listed below.

The BlackBerry 10 file system

In the Momentics IDE for BlackBerry, in the Target File System Navigator view, the application working directory is indicated by the Sandboxes/<appname> directory.

Folder Description

app

read-only

Contains files installed with your application. These files are packaged with your .bar file.

app/native

read-only

Contains the application binary and other application resources.

app/native/assets

read-only

Contains application assets, such as .qml files, images, and media.

data

read-write

Contains the application's private data. This is the application's home directory.

db

read-only

Contains the application's database files.

logs

read-write

Contains system logs for an application. stderr and stdout are redirected to this directory.

shared

read-only

Contains subfolders that contain shared data grouped by type. An application can write to subfolders of this directory only if the access_shared permission is specified.

shared/books

read-write

Contains eBook files that can be shared between applications.

shared/camera

read-write

Contains images taken using the Camera application that can be shared between applications.

shared/documents

read-write

Contains documents that can be shared between applications.

shared/downloads

read-write

Contains web browser downloads that can be shared between applications.

shared/Dropbox

read-write

Contains files located in the user's Dropbox account.

shared/misc

read-write

Contains files that don't belong in any other category. These files can be shared between applications.

shared/music

read-write

Contains music files that can be shared between applications.

shared/photos

read-write

Contains photos that can be shared between applications.

shared/print

read-write

Contains news and print articles that can be shared between applications.

shared/videos

read-write

Contains videos that can be shared between applications.

shared/voice

read-write

Contains audio recordings that can be shared between applications.

sharewith

read-write

Contains files that the application can share with other applications by using the Invocation framework.

tmp

read-write

Contains the application's temporary working files. The application should remove these files regularly. The BlackBerry 10 OS may remove these files when the application isn't running.

Prerequisites

To give your application write access to the shared subfolders, you must set the Shared Files permission (access_shared) in your bar-descriptor.xml file.

The working directory

The working directory (also known as the current directory or the sandbox) is the root directory for your application. It contains all of the files installed with your application, provides a location for you to store additional content, and provides access to a number of shared folders that are accessible to all applications. Applications cannot create new directories or files at the root of the working directory, but they can in some of its subfolders.

If you need the absolute path to a particular directory, you can retrieve it in a couple of different ways. In Cascades, the QDir::currentPath() function returns a path to the application working directory. In C, getcwd() returns the same path. The paths that these functions return have the following format: /accounts/1000/appdata/<namespace.application> .

Cascades also provides functions for retrieving the path to the app's data directory using QDir::homePath() and its tmp directory using QDir::tempPath(). To access these directories using C, you must call getcwd() to get the application working directory and use string concatenation to build the full paths yourself.

Creating new files and directories

Here's an example that shows how to create a new directory in the application working directory, create a file in the new directory, and read the file.

#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <limits.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <errno.h>

#define MAX_BUFF_LENGTH PATH_MAX + 1
#define CREATE_DIRECTORY_SUCCESS 0
#define WRITE_DATA_SUCCESS 1
/*
 * This function creates a directory within the current working directory,
 * creates a file within the newly created directory, and
 * reads the contents of the newly created file and displays it in the console.
 */
int runFileIO_sample_01()
{
    int rc;

    /* Variable to hold the path, and later the path and filename */
    char cwd[MAX_BUFF_LENGTH];

    /* Variable used to access a file in the assets directory */
    char assetfilepath[MAX_BUFF_LENGTH];

    /* Get the current working directory */
    getcwd(cwd, MAX_BUFF_LENGTH);

    if(cwd != NULL)
    {
        /* Save for second part of this sample */
        strcpy(assetfilepath, cwd);

        /* Create path for new directory */
        char* dirname = "test_dir";
        strcat(cwd, "/data/");
        strcat(cwd, dirname);

        /* Create a new directory */
        rc = mkdir(cwd, S_IRUSR | S_IWUSR | S_IXUSR /* User permissions  */
                | S_IRGRP | S_IWGRP | S_IXGRP       /* Group permissions */
                | S_IROTH | S_IXOTH);               /* Other permissions */

        if (rc != CREATE_DIRECTORY_SUCCESS)
        {
            /* Error occurred */
            printf("Directory Error: %s", strerror(errno));
            exit(1);
        }

        char *filename = "data.txt";
        strcat(cwd, "/");
        strcat(cwd, filename);

        /*
         * Create or open a new file in the new directory
         *   a = append: The file is opened for output at the end of the file
         *   b = binary: The file is opened as a binary file
         *   + = update: The file is opened for update; any output operations
         *               write data at the end of the file
         */
        FILE *pFile;

        /* Open file for appending */
        pFile = fopen(cwd, "ab+");

        if (pFile != NULL)
        {

            /* Set the data to write to the new data file */
            char datastr[] = "Sample text being written to the new data file.\n";

            /* Write the data to the file */
            if(WRITE_DATA_SUCCESS == fwrite(datastr, strlen(datastr), 1, pFile))
            {
                /* Create a buffer to use for file reading */
                char buf[BUFSIZ];

                /* Seek to the beginning of the file */
                fseek(pFile, SEEK_SET, 0);

                printf("Reading TXT file ...\n\n");

                /* Read the file contents */
                while(!feof(pFile))
                {
                    /* Clean the buffer */
                    memset(buf, '\0', BUFSIZ);

                    /* Read a portion of the file */
                    fread(buf, strlen(datastr), 1, pFile);

                    /* Display the portion read*/
                    printf("%s", buf);
                }
                printf("\n");

                /* Clean up */
                fclose(pFile);
                pFile = NULL;
            }
            else
            {
                /* Error occurred */
                printf("Error: %s", strerror(errno));
                exit(1);
            }
        }
        else
        {
            /* Error occurred */
            printf("Error: %s", strerror(errno));
            exit(1);
        }
    }
    else
    {
        /* Error occurred */
        printf("Error: %s", strerror(errno));
        exit(1);
    }

    return 0;
}

The assets directory

Any assets that you have in your app (for example, images, sounds, .qml files, and so on) must be kept in the assets folder in your project. In the file system, content in the assets folder for an application can be found in the app/native/assets directory.

Because they're packaged with the application, assets are generally considered to be always available and immediately ready to be displayed, unlike other types of content that might be generated by the application or retrieved from a remote location.

Cascades has a shortcut that you can use to retrieve the path to the assets directory. To reference items in the assets directory, append the file name of your asset to asset:///. To reference assets in C, you must use string concatenation to build the full path yourself.

Here are some examples of how to load items from the assets directory. The items need to be located at the root of the assets directory in your project.

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>

#define MAX_BUFF_LENGTH PATH_MAX + 1
/*
 * This function loads an image (or any other media file) from the assets
 * directory into memory
 */
int runFileIO_sample_02()
{
    char imgfilepath[MAX_BUFF_LENGTH];
    FILE* pFile;

    if(NULL == getcwd(imgfilepath, MAX_BUFF_LENGTH))
    {
        printf("Error: %s", strerror(errno));
        exit(1);
    }

    /* Set the path for the image file to open
     * in the assets directory */
    strcat(imgfilepath, "/app/native/assets/myimg.jpg");

    /* Open the image file for reading binary data */
    pFile = fopen(imgfilepath, "rb");

    if(pFile == NULL)
    {
        printf("Error: %s", strerror(errno));
        exit(1);
    }

    return 0;
}

The shared directory

The shared folder contains a set of subfolders that contain shared data grouped by type.

An application only has read access in this directory, but it can read and write to subfolders if the correct permission is applied.

To give your application write access to the shared subfolders, you must set the Shared Files permission (access_shared) in your bar-descriptor.xml file.

Screen showing the Shared Files check box.

For example, if you're creating a picture viewer application, you might want to access the files in the shared/camera directory. Here's an example of how to load items from the shared directory using absolute paths:

#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>

#define MAX_BUFF_LENGTH PATH_MAX + 1
/*
 * This function loads an image (or any other media file) from the shared/camera
 * directory into memory
 */
int runFileIO_sample_03()
{
    char imgfilepath[MAX_BUFF_LENGTH];
    FILE* pFile;

    if(NULL == getcwd(imgfilepath, MAX_BUFF_LENGTH))
    {
        printf("Error: %s", strerror(errno));
        exit(1);
    }

    /* Set the path for the image file to open
     * in the shared/camera directory */
    strcat(imgfilepath, "/shared/camera/myimg.jpg");

    /* Open the image file for reading binary data */
    pFile = fopen(imgfilepath, "rb");

    if(pFile == NULL)
    {
        printf("Error: %s", strerror(errno));
        exit(1);
    }

    return 0;
}

Copying files to a read-write directory

A common app requirement is to copy a file from the assets directory to a read-write directory so the app can modify the data. Here are some different examples for copying to various directories.

Copying to any of the shared directories requires the Shared files (access_shared) permission in your bar_descriptor.xml file.

#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>

#define MAX_BUFF_LENGTH PATH_MAX + 1
/*
 * This function copies files from the read-only assets directory and
 * stores them in the data and shared directories for writing.
 */
int runFileIO_sample_04()
{
    char cwd[MAX_BUFF_LENGTH];
    char targetjsonfilepath[MAX_BUFF_LENGTH];
    char destjsonfilepath[MAX_BUFF_LENGTH];
    char targetdbfilepath[MAX_BUFF_LENGTH];
    char destdbfilepath[MAX_BUFF_LENGTH];
    FILE* ptargetjsonfile;
    FILE* pdestjsonfile;
    FILE* ptargetdbfile;
    FILE* pdestdbfile;
    char buffer[BUFSIZ] = { '\0' }; /* BUFSIZ defined in stdio.h */

    /* Get the current working directory path */
    getcwd(cwd, MAX_BUFF_LENGTH);

    /*
     * --- Copy a JSON file from the assets directory to the data directory ---
     */

    /* Clear the memory space for a temporary path variable */
    memset(targetjsonfilepath, '\0', sizeof(targetjsonfilepath));

    /* Clear the memory space for a temporary path variable */
    memset(destjsonfilepath, '\0', sizeof(destjsonfilepath));

    /* Copy the path of the current working directory
     * into a temporary variable */
    strcpy(targetjsonfilepath, cwd);

    /* Copy the path of the current working directory
     * into a temporary variable */
    strcpy(destjsonfilepath, cwd);

    /* Set the target file path */
    strcat(targetjsonfilepath, "/app/native/assets/mydata.json");

    /* Set the destination file path */
    strcat(destjsonfilepath, "/data/mydata.json");

    /* Open the target file for reading binary data */
    ptargetjsonfile = fopen(targetjsonfilepath, "rb");

    if(ptargetjsonfile != NULL)
    {
        /* Open (create) the destination file for writing binary data */
        pdestjsonfile = fopen(destjsonfilepath, "wb");

        if(pdestjsonfile != NULL)
        {
            /* Read the file contents */
            while(!feof(ptargetjsonfile))
            {
                fread(buffer, BUFSIZ, 1, ptargetjsonfile);
                fwrite(buffer, strlen(buffer), 1, pdestjsonfile);
            }

            fclose(pdestjsonfile);

            /* Delete the original file */
            remove(targetjsonfilepath);

            fclose(ptargetjsonfile);
            ptargetjsonfile = NULL;
        }
        else
        {
            /* Error occurred */
            printf("Error: %s", strerror(errno));
            fclose(ptargetjsonfile);
            ptargetjsonfile = pdestjsonfile = NULL;
            exit(1);
        }
    }
    else
    {
        /* Error occurred */
        printf("Error: %s", strerror(errno));
        exit(1);
    }

    /*
     * --- Copy a DB file from the assets directory to the shared/misc directory ---
     */

    /* Clear the memory space for a temporary path variable */
    memset(targetdbfilepath, '\0', sizeof(targetdbfilepath));

    /* Clear the memory space for a temporary path variable */
    memset(destdbfilepath, '\0', sizeof(destdbfilepath));

    /* Copy the path of the current working directory
     * into a temporary variable */
    strcpy(targetdbfilepath, cwd);

    /* Copy the path of the current working directory
     * into a temporary variable */
    strcpy(destdbfilepath, cwd);

    /* Set the target file path */
    strcat(targetdbfilepath, "/app/native/assets/mydata.db");

    /* Set the destination file path */
    strcat(destdbfilepath, "/shared/misc/mydata.db");

    /* Open the target file for reading binary data */
    ptargetdbfile = fopen(targetdbfilepath, "rb");

    if(ptargetdbfile != NULL)
    {
        /* Open (or create) the destination file for writing binary data */
        pdestdbfile = fopen(destdbfilepath, "wb");

        if(pdestdbfile != NULL)
        {
            /* Read the file contents */
            while(!feof(ptargetdbfile))
            {
                fread(buffer, BUFSIZ, 1, ptargetdbfile);
                fwrite(buffer, strlen(buffer), 1, pdestdbfile);
            }

            fclose(pdestdbfile);

            /* Delete the original file */
            remove(targetdbfilepath);

            fclose(ptargetdbfile);
            ptargetdbfile = NULL;
        }
        else
        {
            /* Error occurred */
            printf("Error: %s", strerror(errno));
            fclose(ptargetdbfile);
            ptargetdbfile = pdestdbfile = NULL;
            exit(1);
        }
    }
    else
    {
        /* Error occurred */
        printf("Error: %s", strerror(errno));
        ptargetdbfile = NULL;
        exit(1);
    }

    return 0;
}

Last modified: 2014-09-30



Got questions about leaving a comment? Get answers from our Disqus FAQ.

comments powered by Disqus