Wraps the Cordova (and Chrome) File API in convenient functions (that return a Promise)
Are you entangled in a async callback mess to get even the simplest task done? Wait no longer -- here is cordova-promise-fs!
# fetch code using bower
bower install cordova-promise-fs
bower install bluebird # a library that follows the Promise/A+ spec
# ...or npm...
npm install cordova-promise-fs
npm install bluebird # a library that follows the Promise/A+ spec
# install Cordova and plugins
cordova platform add ios
cordova plugin add cordova-plugin-file
cordova plugin add cordova-plugin-file-transfer # optional
IMPORTANT: For iOS, use Cordova 3.7.0 or higher (due to a bug that affects requestFileSystem).
Or just download and include CordovaPromiseFS.js.
var fs = CordovaPromiseFS({
persistent: true, // or false
storageSize: 20*1024*1024, // storage size in bytes, default 20MB
concurrency: 3 // how many concurrent uploads/downloads?
Promise: require('promiscuous') // Your favorite Promise/A+ library!
});
The Promise option expects a Promise library that follows the Promise/A+ spec, such as bluebird (github, download), promiscuous (github,file) or Angular's $q.
Note on concurrency: Concurrent uploads/downloads completely trash your mobile application. That's why I've put a concurrency limit on the number of downloads/uploads. Meteor sets this number on 30. In my experimental testing, I found 3 much more reasonable.
fs.exists(filename) // checks if file exists. returns fileEntry or false.
fs.file(filename) // returns a fileEntry
fs.dir(path) // returns a dirEntry
fs.list(path,optionString)// return array with filenames (including path)
optionString = 'r' // recursive list
optionString = 'd' // only list directories
optionString = 'f' // only list files
optionString = 'e' // return results as FileEntry/DirectoryEntry (instead as path-string)
optionString = 'rfe' // mix options! return entries of all files, recursively
fs.read(filename) // returns text-content of a file
fs.readJSON(filename) // returns JSON-parsed contents of a file
fs.toUrl(filename) // returns URL to be used in js/html/css (file://....)
fs.toInternalURL(filename)// returns cordova internal URL (cdvfile://....)
fs.toDataURL(filename) // returns Base64 encoded Data URI
fs.write(filename,data) // writes a Blob, a String, or data (as JSON). Ensures directory exists.
fs.create(filename) // creates a file
fs.ensure(path) // ensures directory exists
fs.move(src,dest) // move from src to dist. Ensures dest directory exists.
fs.moveDir(src,dest)
fs.copy(src,dest) // copy from src to dist. Ensures dest directory exists.
fs.remove(src) // removes file. Resolves even if file was already removed.
fs.remove(src,true) // removes file. Rejects when file does not exist.
fs.removeDir(path)
FileTransfers with automatric retry and concurrency limit!
var promise = fs.upload(source,destination,[options],[onprogress]);
var promise = fs.upload(source,destination,[onprogress]);
var promise = fs.download(source,destination,[options],[onprogress]);
var promise = fs.download(source,destination,[onprogress]);
options.trustAllHosts
options.retry = [1000,2000,3000] // retry attemps: millisecond to wait before trying again.
// plus all normal cordova-file-transfer options
// upload/download augments the promise with two extra functions:
promise.progress(function(progressEvent){...})
promise.abort();
// Gotcha: progress and abort() are unchainable;
fs.upload(...).then(...) // won't return the augmented promise, just an ordinary one!
fs.fs // returns promise for the FileSystem
fs.filename(path) // converts path to filename (last part after /)
fs.dirname(path) // converts path dirname (everything except part after last /)
fs.deviceready // deviceready promise
fs.options // options
fs.isCordova // is Cordova App?
In CordovaPromiseFS, all filenames and paths are normalized:
- Directories should end with a
/
. - Filenames and directories should never start with a
/
. "./"
is converted to""
- ".." and "." are resolved.
This allows you to concatenate normalized paths, i.e.
normalize('dir1/dir2') === normalize('dir1') + normalize('dir2') === 'dir1/dir2/';
If you're storing or saving paths, it is recommended to normalize
them first to avoid comparison problems. (i.e. paths are not recognized as the same because of a missing trailing slash).
Beware: the original entry.fullPath
might return a path which starts with a /
. This causes problems on Android, i.e.
var path = filesystem.root.fullPath; // returns something starting with a `/`
filesystem.root.getDirectory(path); // NullPointer error in android. Stupid!
This problem is solved in CordovaPromiseFS.
- Added Crosswalk
- Bugfix: list will return more than 100 entries
- Fixed bug: download/upload support for different Cordova FileSystems.
- Fixed bug in list function, thanks @sebastian-greco
- Improved code readability of transfer, thanks @youjenli
- There is no this, thanks @m0ppers
- Accept string as FileSystem, thanks @dortzur
- Normalize ".." in paths, thanks @starquake
- Merged pull request from @Ijzerenhein. Fixed Chrome Persistent storage quota issue and added directory methods.
- Merged pull request from @jakgra. Now you can write to hidden folders on Android. Thanks!
- Minor improvements in upload
- Support for other fileSystems (undocumented hack)
- Normalize path everywhere.
- Added test-suite, fixed few minor bugs.
- bugfix toInternalURL functions and fix download argument order
- Chrome Support!
- Use
webpack
for the build proces - Fixed many small bugs
- Various small changes
- Added
CordovaPromiseFS.js
for everybody who does not use Browserify/Webpack
- Added
list
options (listr
ecursively, onlyf
iles, onlyd
irectories, return result ase
ntries)
- Added
upload
anddownload
methods with concurrency limit
Convert CommonJS to a browser-version:
npm install webpack -g
npm run-script prepublish
Run tests: Navigate to /test/index.html
, for example:
npm install static -g
static .
# http://localhost:8080/test/index.html
Feel free to contribute to this project in any way. The easiest way to support this project is by giving it a star.
- @markmarijnissen
- http://www.madebymark.nl
- info@madebymark.nl
© 2014 - Mark Marijnissen