Skip to content

Instantly share code, notes, and snippets.

@john-doherty
Last active August 2, 2023 10:32
Show Gist options
  • Save john-doherty/6a9bf0f6b5eb77fb2bd332571a84c7c2 to your computer and use it in GitHub Desktop.
Save john-doherty/6a9bf0f6b5eb77fb2bd332571a84c7c2 to your computer and use it in GitHub Desktop.
An easy way to read/write files in Cordova
var fileStorage = {
/**
* Saves a file on the device
* @param {string} name - filename (can include sub folders)
* @param {string} data - file contents
* @param {boolean} useSandbox - uses protected sandbox if true, otherwise external (default false)
* @returns {Promise} executes .then with saved file path as first param
*/
write: function (name, data, useSandbox) {
var nameParts = name.split('/');
var nameIndex = 0;
var dir = (useSandbox) ? cordova.file.dataDirectory : cordova.file.externalDataDirectory;
return new Promise(function (resolve, reject) {
var fail = function (msg, error) {
reject('Write failed on ' + msg + ', code: ' + error.code);
};
var fileUrl = '';
var gotFileWriter = function (writer) {
writer.onwrite = function () {
resolve(fileUrl);
//resolve(writer.localURL);
};
writer.onerror = fail.bind(null, 'gotFileWriter');
writer.write(data);
};
var gotFileEntry = function (fileEntry) {
fileUrl = fileEntry.toURL();
fileEntry.createWriter(gotFileWriter, fail.bind(null, 'createWriter'));
};
var gotDirectory = function (directory) {
nameIndex++;
if (nameIndex === (nameParts.length - 1)) {
directory.getFile(nameParts[nameIndex], { create: true, exclusive: false }, gotFileEntry, fail.bind(null, 'gotDirectory - getDirectory'));
}
else {
directory.getDirectory(nameParts[nameIndex], { create: true }, gotDirectory, fail.bind(null, 'gotDirectory - getFile'));
}
};
var gotFileSystem = function (fileSystem) {
if (nameParts.length > 1) {
fileSystem.getDirectory(nameParts[nameIndex], { create: true }, gotDirectory, fail.bind(null, 'gotFileSystem - getDirectory'));
}
else {
fileSystem.getFile(name, { create: true, exclusive: false }, gotFileEntry, fail.bind(null, 'gotFileSystem - getFile'));
}
};
window.resolveLocalFileSystemURL(dir, gotFileSystem, fail.bind(null, 'requestFileSystem'));
});
},
/**
* Reads a file from the device
* @param {string} name - filename (can include sub folders)
* @param {boolean} useSandbox - uses protected sandbox if true, otherwise external (default false)
* @returns {Promise} executes .then with file content as first param
*/
read: function (name, useSandbox) {
var dir = (useSandbox) ? cordova.file.dataDirectory : cordova.file.externalDataDirectory;
return new Promise(function (resolve, reject) {
var fail = function (msg, error) {
reject('Read failed on ' + msg + ', code: ' + error.code);
};
var gotFile = function (file) {
var reader = new FileReader();
reader.onloadend = function (evt) {
resolve(evt.target.result);
};
reader.onerror = fail.bind(null, 'gotFile');
reader.readAsText(file);
};
var gotFileEntry = function (fileEntry) {
fileEntry.file(gotFile, fail.bind(null, 'gotFileEntry'));
};
window.resolveLocalFileSystemURL(dir + name, gotFileEntry, fail.bind(null, 'resolveLocalFileSystemURL'));
});
},
/**
* Removes a file from the device
* @param {string} name - filename (can include sub folders)
* @param {boolean} useSandbox - uses protected sandbox if true, otherwise external (default false)
* @returns {Promise} .then is executed if successful otherwise .catch with error message
*/
removeFile: function (name, useSandbox) {
var dir = (useSandbox) ? cordova.file.dataDirectory : cordova.file.externalDataDirectory;
return new Promise(function (resolve, reject) {
var fail = function (msg, error) {
reject('Remove file failed on ' + msg + ', code: ' + error.code);
};
var gotFileEntry = function (fileEntry) {
fileEntry.remove(function () {
resolve();
}, fail.bind(null, 'remove'));
};
window.resolveLocalFileSystemURL(dir + name, gotFileEntry, fail.bind(null, 'resolveLocalFileSystemURL'));
});
},
/**
* Removes an entire directory from the device
* @param {string} name - directory name/path to remove
* @param {boolean} useSandbox - uses protected sandbox if true, otherwise external (default false)
* @returns {Promise} .then is executed if successful otherwise .catch with error message
*/
removeDirectory: function (name, useSandbox) {
var dir = (useSandbox) ? cordova.file.dataDirectory : cordova.file.externalDataDirectory;
return new Promise(function (resolve, reject) {
var fail = function (msg, error) {
reject('Remove directory failed on ' + msg + ', code: ' + error.code);
};
var gotDirectory = function (directory) {
directory.removeRecursively(function () {
resolve();
}, fail.bind(null, 'removeRecursively'));
};
window.resolveLocalFileSystemURL(dir + name, gotDirectory, fail.bind(null, 'resolveLocalFileSystemURL'));
});
}
};
@john-doherty
Copy link
Author

Here is a quick example of how to use the singleton above to write files:

// the object you want to save
var objectToSave = { firstName: 'John', lastName: 'Doherty' };

// the filename and extension you want to use
var filename = 'whatever.txt';

// the data to write (convert JSON object to a string)
var data = JSON.stringify(objectToSave);

// call write with params, .then executes with the filePath once complete
fileStorage.write(filename, data).then(function(filePath) {
     console.log(filePath);
})
.catch(function(err) {
     // this executes if something went wrong
     console.warn(err);
});

@john-doherty
Copy link
Author

This will use external (unprotected storage) by default, set useSandbox to true to save files in a protected location where users and external app are unable to access them.

@drannex42
Copy link

You should convert this to a proper repository, there is some good stuff here that others should be able to find a lot easier.

@john-doherty
Copy link
Author

Good point @drannex42, I've created a repo cordova-file-storage. Let me know if you have any suggestions/tweaks.

@MasterB0t
Copy link

Im getting an error whenever I try to read a file. "Read failed on resolveLocalFileSystemURL, code: 1"
I was able to write the file with/without sandbox , I can see the file in the emulator but whenever I try to read it I get that error.

I have add this in confix.xml

also on AndroidManifest.xml

Don't know if I have to do add anything else

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment