Cordova File System Access

Beyond simple key-value storage, some apps need real files — saving a downloaded document, writing a log, caching a large dataset, or exporting user-generated content. The File plugin, cordova-plugin-file, gives your JavaScript code access to the device's file system, but through a deliberately sandboxed model rather than free rein over device storage. This page covers that model, the directories you're given, and full worked examples for writing and reading a text file.

Installing the Plugin

cordova plugin add cordova-plugin-file

The Sandboxed File System Model

Modern mobile operating systems don't let apps read and write arbitrary files anywhere on the device — that would be a serious privacy and security risk. Instead, each app is given its own private, isolated area of storage, plus a few specific shared locations it can request access to. The File plugin exposes this model to your JavaScript as a set of directory constants, each pointing to a URL you can use as the starting point for file operations. You don't construct these paths yourself — you ask Cordova for the right one for what you're trying to do.

Key Directory Constants

ConstantWhat it points to
cordova.file.dataDirectoryPersistent, app-private storage — files here survive app restarts and are only ever cleared if the app itself deletes them or the app is uninstalled. This is the right place for data your app needs to keep long-term.
cordova.file.cacheDirectoryTemporary, app-private storage that the OS is allowed to clear on its own when the device is low on space — appropriate for regenerable data like thumbnails or downloaded content you can fetch again
cordova.file.externalRootDirectoryAndroid-specific: the root of external/shared storage, visible outside your app (for example, in a file manager). Requires appropriate storage permissions and is not available on iOS.
Pick the directory deliberately: reaching for dataDirectory by default is usually the safest choice for anything you want to keep — use cacheDirectory only for data you're fully prepared to lose without asking the user first.

Full Example: Writing a Text File

Writing a file is a multi-step process: first resolve the target directory into a DirectoryEntry, then get (or create) the specific file inside it as a FileEntry, then open a FileWriter on that entry to actually write content:

function writeTextFile() {
    window.resolveLocalFileSystemURL(cordova.file.dataDirectory, onDirectorySuccess, onFileError);
}

function onDirectorySuccess(dirEntry) {
    dirEntry.getFile('notes.txt', { create: true }, onFileGot, onFileError);
}

function onFileGot(fileEntry) {
    fileEntry.createWriter(onWriterReady, onFileError);
}

function onWriterReady(writer) {
    writer.onwriteend = function() {
        console.log('File written successfully');
    };
    writer.onerror = onFileError;
    writer.write('This text was saved from a Cordova app.');
}

function onFileError(error) {
    console.log('File error: ' + error.code);
}

Note the { create: true } option passed to getFile() — it tells Cordova to create the file if it doesn't exist yet, rather than failing. Passing { create: true, exclusive: true } instead would fail if the file already exists, useful when you specifically want to avoid overwriting something.

Full Example: Reading a File Back

Reading a file follows a similar resolve-then-act pattern, but ends with a standard web FileReader to actually pull the text content out of the file:

function readTextFile() {
    window.resolveLocalFileSystemURL(cordova.file.dataDirectory + 'notes.txt', onReadFileEntry, onFileError);
}

function onReadFileEntry(fileEntry) {
    fileEntry.file(function(file) {
        var reader = new FileReader();

        reader.onloadend = function() {
            console.log('File contents: ' + this.result);
        };

        reader.onerror = onFileError;
        reader.readAsText(file);
    }, onFileError);
}

function onFileError(error) {
    console.log('File error: ' + error.code);
}

Handling Common File Errors

The error object passed to a file error callback carries a numeric code you can inspect to distinguish common failure cases:

SituationWhat typically happens
File not foundCalling getFile() without { create: true } on a file that doesn't exist yet fails with a "not found" error code — decide up front whether a missing file should be created or treated as a real error
Permission deniedEspecially relevant for externalRootDirectory on Android, where the required storage permission may not have been granted by the user yet
Quota exceededWriting more data than the device has space or quota for fails with its own error code — worth handling explicitly if your app writes larger files
Always pass an error callback: every one of the file operations above accepts a failure callback as its final argument. Skipping it doesn't make failures disappear — it just means a failed read or write happens silently, with no way for your app (or you, while debugging) to know it happened.
Up next: Continue to Local Storage & Persistence for lighter-weight key-value storage that complements the File plugin.