I am using ngCordova extension for AngularJS. Till now I have found it a very powerful extension, which helps you create AngularJS + Cordova applications in a go. I wanted to use File read/write functionality in one of my app. I have successfully implemented the File Reading functionality using ngCordova. Now, I want to know the way to write the data to a file. I would be thankful if I get any demo code for the same.
You should be able to with ngCordova,
$cordovaFile.writeFile(filePath).then(function(result) {
// Success!
}, function(err) {
// An error occured. Show a message to the user
});
Iâm also looking for an answer to the question asked.
I donât understand where to put the data that you actually want to write.
As far as I can see, the code above writes a blank file.
How would I for example write some JSON to a file?
Iâm looking for a real example of writing data as well. same as steviewevie. hopefully one that suggests a standard file path as well
Had the same problem, searched the ng-cordova.js file to see what was up.
The docs are missing two arguments for the writeFile function.
Try this, it worked for me:
$cordovaFile.writeFile( 'file.txt', data, {'append':false} ).then( function(result) {
// Success!
}, function(err) {
// An error occured. Show a message to the user
});
Iâm having problems writing a dataURL to a file.jpg on iOS. I keep getting error {"code":5}
I know I should convert the dataURL to a Blob, but that shouldnât keep me from writing a file.
Also, if I just provide a filename (no path) the save is successful, but a checkFile still gives me the same error {"code":5}
any ideas?
// INFO: Local cache folder opened: file:///var/mobile/Containers/Data/Application/[UUID]/tmp/imgcache/
//DOESN'T WORK AT ALL
//filePath=file:///var/mobile/Containers/Data/Application/[UUID]/tmp/imgcache/12345.jpg
//dataURL.slice(0,50)=data:image/jpg;base64,/9j/4AAQSkZJRgABAQEASABIAAD/4
return $cordovaFile.writeFile(filePath, dataURL, {
'append': false
}).then(function(result) {
console.log("$ngCordovaFile writeFile SUCCESS");
console.log(result);
return $q.when(result);
}, function(error) {
console.log("$ngCordovaFile writeFile ERROR");
// $ngCordovaFile writeFile ERROR
console.log(error);
// {"code":5}
return $q.reject(error);
});
//works for filePath=12345.jpg, cdvfile://localhost/persistent/12345.jpg
//dataURL.slice(0,50)=data:image/jpg;base64,/9j/4AAQSkZJRgABAQEASABIAAD/4
return $cordovaFile.writeFile(filePath, someBlob, {
'append': false
}).then(function(result) {
console.log("$ngCordovaFile writeFile SUCCESS");
console.log(result);
//{"type":"writeend","bubbles":false,"cancelBubble":false,"cancelable":false,"lengthComputable":false,"loaded":0,"total":0,"target":{"fileName":"","length":344286,"localURL":"cdvfile://localhost/persistent/12345.jpg","position":344286,"readyState":2,"result":null,"error":null,"onwritestart":null,"onprogress":null,"onwrite":null,"onabort":null,"onerror":null}}
return $q.when(result);
}, function(error) {
console.log("$ngCordovaFile writeFile ERROR");
console.log(error);
return $q.reject(error);
}).then(function(result) {
filePath = result['target']['localURL'];
console.log("\n\n >>> $ngCordovaFile.checkFile() for file=" + filePath);
// >>> $ngCordovaFile.checkFile() for file=cdvfile://localhost/persistent/12345.jpg
return $cordovaFile.checkFile(filePath);
}).then(function(result) {
console.log(result);
console.log("$ngCordovaFile says file EXISTS file=" + filePath + "\n\n");
return result;
})["catch"](function(error) {
console.log(error);
//{"code":5}
console.log("$ngCordovaFile.checkFile() says DOES NOT EXIST, file=" + filePath + "\n\n");
//$ngCordovaFile.checkFile() says DOES NOT EXIST, file=cdvfile://localhost/persistent/12345.jpg
return $q.reject(error);
});
I hope this will help you out:
app.controller(âTestCtrlâ, [â$scopeâ, â$qâ, â$cordovaFileâ,
function($scope, $q, $cordovaFile) {
console.log('TestCtrl');
/*
List dir test and remove all dirs and files in test to start over again the test
*/
function ClearDirectory() {
console.log('ClearDirectory');
$cordovaFile.listDir(fileDir + 'test').then( function(entries) {
console.log('listDir: ', entries);
}, function(err) {
console.error('listDir error: ', err);
});
$cordovaFile.removeRecursively(fileDir + 'test')
.then( function() {
console.log(trinlDir + ' recursively removed');
},
function(err) {
console.log(fileDir + ' error: ', err);
});
}
/*
Here some examples with proper filepath
*/
function testFS() {
// Download file from 'http://www.yourdomain.com/test.jpg' to test/one/test.jpg on device Filesystem
var hostPath = 'http://www.yourdomain.com/test.jpg';
var clientPath = fileTransferDir + 'test/one/test.jpg';
var fileTransferOptions = {};
$cordovaFile.downloadFile(hostPath, clientPath, true, fileTransferOptions).then (function() {
});
// Create dir test
$cordovaFile.createDir(fileDir + 'test/').then( function(dirEntry) {
});
// Create dir aganin in dir test
$cordovaFile.createDir(fileDir + 'test/one/').then( function(dirEntry) {
});
// Create empty file test.txt in test/again/
$cordovaFile.createFile(fileDir + 'test/one/test.txt', true).then( function(fileEntry) {
});
// List of files in test/again
$cordovaFile.listDir(fileDir + 'test/one/').then( function(entries) {
console.log('list dir: ', entries);
});
// Write some text into file
$cordovaFile.writeFile(fileDir + 'test/one/test.txt', 'Some text te test filewrite', '').then( function(result) {
});
// Read text written in file
$cordovaFile.readAsText(fileDir + 'test/one/test.txt').then( function(result) {
console.log('readAsText: ', result);
});
}
function testQ() {
var hostPath = 'http://www.yourdomain.com/test.jpg';
var clientPath = fileTransferDir + 'test/one/test.jpg';
var fileTransferOptions = {};
$q.all([
$cordovaFile.downloadFile(hostPath, clientPath, true, fileTransferOptions),
$cordovaFile.createDir(fileDir + 'test/'),
$cordovaFile.createDir(fileDir + 'test/two/'),
$cordovaFile.createFile(fileDir + 'test/one/test.txt', true),
$cordovaFile.listDir(fileDir + 'test/one/'),
$cordovaFile.writeFile(fileDir + 'test/one/test.txt', 'Some text te test filewrite', ''),
$cordovaFile.readAsText(fileDir + 'test/one/test.txt')
]).then( function(result) {
console.log('testQ result: ', result);
});
}
/*
Here is what I am using for my Android and IOS apps
Keep attention to a couple of things:
- Android and IOS have other directorynames for files
- $cordovaFile functions prefixes all pathnames with root
$cordovaFileTransfer functions needs absolute pathnames
Here I create the prefixes for File functions and FileTransfer functions for Android and IOS
*/
$ionicPlatform.ready(function() {
if (ionic.Platform.isAndroid()) {
console.log('cordova.file.externalDataDirectory: ' + cordova.file.externalDataDirectory);
myFsRootDirectory1 = 'file:///storage/emulated/0/'; // path for tablet
myFsRootDirectory2 = 'file:///storage/sdcard0/'; // path for phone
fileTransferDir = cordova.file.externalDataDirectory;
if (fileTransferDir.indexOf(myFsRootDirectory1) === 0) {
fileDir = fileTransferDir.replace(myFsRootDirectory1, '');
}
if (fileTransferDir.indexOf(myFsRootDirectory2) === 0) {
fileDir = fileTransferDir.replace(myFsRootDirectory2, '');
}
console.log('Android FILETRANSFERDIR: ' + fileTransferDir);
console.log('Android FILEDIR: ' + fileDir);
}
if (ionic.Platform.isIOS()) {
console.log('cordova.file.documentsDirectory: ' + cordova.file.documentsDirectory);
fileTransferDir = cordova.file.documentsDirectory;
fileDir = '';
console.log('IOS FILETRANSFERDIR: ' + fileTransferDir);
console.log('IOS FILEDIR: ' + fileDir);
}
if (ionic.Platform.isAndroid() || ionic.Platform.isIOS()) {
ClearDirectory();
testFS();
// Other functions here
}
});
}]);
thank pcr:
$cordovaFile.writeFile donât accept cordova.file.externalDataDirectory, you must remove root dir.
fileDir = cordova.file.externalDataDirectory.replace(cordova.file.externalRootDirectory, '');
var filePath = fileDir+"allNews.txt";
//or filePath = "allNews.txt";
$cordovaFile.writeFile(filePath, data, options).then(function(result) {
//success
}, function(err) {
// An error occurred. Show a message to the user
});
You are absolutely right. In my code writeFile doesnât use directly cordova.externalDataDirectory. In my code you see that path in my ngCordova functions use a prefix. Scroll down in my code. At the very end I define prefixes for platform Android or IOS. For Android devices there are some other things to do because, for example: Samsung SII phone uses another root than Samsung Tab 3. Maybe there are some other devices with specific rootdir. If you read my code at the end you should what to to if a device uses another root. Simply add a rootDir that should be removed for using ngCordova functions.These prefixes I use in all my ngCordova functions. I tested this approach very often.
thank pcr, i use your code in my project.
@pcr Between this code you posted and my own experiments, it seems to me that the ONLY directory cordovaFile can access on android is the externalDataDirectory�
When I run $cordovaFile.listDir(ââ), I only get paths associated with the externalDataDirectory (storage/sdcard0 on my test phone, as you noted), and I cannot seem to figure out how to point $cordovaFile at other file systems, even though, for example, I can resolve cordova.file.cacheDirectory via window.resolveLocalFileSystemURL, it definitely exists, and has a native url of file:///data/data//cache
Am I missing something?
@nandanrao In my case it is like the:
I use Samnsung SII and Samsung Tab 3. I wanted to use the storage on external SdCard. But for some reason these devices cordova dont detect these sdcards. As a foldback Samsung devices redirct to the internal SdCard. So my code works. I wait for external untill cordova or Samsung has solved this issue.
If you have another device and this dont work you replace externalDataDirectory with dataDirectory. Now you are using directly the internal Storage.
I never tried the cache directory. Iâll try asap and let you knowâŚ
You are right. cordova.file.cacheDirectory doesnât work with my solution. I am not sure if it is my solution. Iâll investigate why?
Did you guys resolve this? I am also trying to write a dataURI to a file but keep getting the encoding errorâŚ
This was really great thank you @pcr.
We came across some odd situations which meant we couldnât use these values:
So we tweaked @pcrâs solution a little. Weâre getting the file system ârootâ DirectoryEntry and using that to generate the relative file path:
var absolutePath = '';
var relativePath = '';
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fileSys) {
fileSys.root.getDirectory('', { create: true, exclusive: false }, function (dir) {
if (ionic.Platform.isAndroid()) {
var rootDirectory = dir.toURL();
absolutePath = cordova.file.externalDataDirectory;
if (absolutePath.indexOf(rootDirectory) === 0) {
relativePath = absolutePath.replace(rootDirectory, '');
}
} else if (ionic.Platform.isIOS()) {
// same as @pcr above
}
}, onFail);
}, onFail);
Thank you @benwood. I hope this workshop for all devices. Then this is the simple way to get the relative path.
@pcr Thanks for this workshop! Iâve followed your suggestions on how to use the file plugin on this thread and all your other posts in various threads regarding ngcordova plugins. I am still getting TypeError: Cannot read property âapplicationDirectoryâ of undefined.
I am developing for the Samsung Tab 4.
My system info:
Cordova CLI: 5.0.0, Ionic Version: 1.0.0-beta.14, Ionic App Lib Version: 0.0.19, OS: Mac OS X Yosemite, Node Version: v0.12.0.
Iâve followed your suggestions on when a plugin is undefined:
- I removed the plugin
- I removed the platform
- I added the platform (android 4.0.0)
- I added the plugin through cordova plugin add cordova-plugin-file in Terminal
- I rebuild my platform
- I updated it
Iâve been googling, stackoverflowing, and forum.ionicframeworkâing for two weeks now, trying to fix this bug.
PLEASE HELP!
Thanks in advance,
William
This is the best approach - root dir can be different on different devices, best to calculate at run-time instead of hard-coding the prefix.
Maybe you can show us the fragment of code the error message refers to?
âUndefinedâ typically means the object is not available (plugin not installed, not injected, etc etc). You can check if the native part is installed under platforms/android/src
. The JS part needs to be in platforms/android/assets/www
. Also make sure the relevant ngCordova service is being injected into your code.
@willy_wonga
I have some questions to help you:
You say an error like âapplicationDirectoryâ of undefined. The undefined object as far as I know is cordova. This means there is something not loaded or you donât wait for device ready. Are you sure ngCordova is loaded (with a script tag in your index.html). Look in Chrome devtools if the has loaded this file.
For me the most made misstake is not waiting for deviceready.