Cordova file plugin - save file in device

30,441

Solution 1

SOLVED:

after several attempts I solved in this way

in config.xml:

<preference name="AndroidPersistentFileLocation" value="Compatibility" />
<preference name="AndroidExtraFilesystems" value="files,cache, sdcard, cache-external, files-external" />

and main function:

window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) {

    //var absPath = "file:///storage/emulated/0/";
    var absPath = cordova.file.externalRootDirectory;
    var fileDir = cordova.file.externalDataDirectory.replace(cordova.file.externalRootDirectory, '');
    var fileName = "somename.txt";
    var filePath = fileDir + fileName;

    fs.root.getFile(filePath, { create: true, exclusive: false }, function (fileEntry) {
        writeFile(fileEntry, BINARY_ARR).then(function(){
          //do something here
        });
    }, function(err) {});
}, function(err) {});

function writeFile(fileEntry, dataObj) {
    return $q(function (resolve, reject) {
        fileEntry.createWriter(function (fileWriter) {
            fileWriter.onwriteend = function () {
                resolve();
            };
            fileWriter.onerror = function (e) {
                reject(e);
            };
            fileWriter.write(dataObj);
        });
    });
}

It seemed that:

<preference name="AndroidPersistentFileLocation" value="Internal" />

that is the default configuration, could not allow the app to write into the external disk (whether physical or emulated). Instead allowed the app only to write into /data/data/{myApp}/files

Solution 2

use this function to write and create new folder

function writeFile(path, filename, blob) {
    return new Promise((resolve, reject) => {
        window.resolveLocalFileSystemURL(cordova.file.externalRootDirectory, function (dirpar) {
            dirpar.getDirectory(path, { create: true }, function (dir) {
                dir.getFile(filename, { create: true, exclusive: false }, function (fileEntry) {
                    fileEntry.createWriter(function (fileWriter) {
                        fileWriter.onwriteend = resolve
                        fileWriter.onerror = reject
                        fileWriter.write(blob);
                    });
                }, reject);
            }, reject);
        }, reject);
    });
}

how to call function

writeFile("AppFolder", 'file.name', blob)

sample download an image and save in folder

var url = "image url"

fetch(url).then(res => res.blob()).then(blob => {

    writeFile("pictures/myapp", url.substring(url.lastIndexOf("/") + 1), blob)
        .then(function () { console.log("file donwloaded.") })
        .catch(function (e) { console.error("error:", e) })

});

Solution 3

Ok so here is the whole explain of how to save the file. Using file plugin cordova:

Suppose you have to Save a file with text "Hello Mr. Vaibhav Mojidra" in a .txt inside internal storage.

so here it goes if you have button click in HTML like this: Now inside SaveFile function:

       var textt="";
       function SaveFile(text)
      {
         textt=text; /* initialize global variable with text to be written in file */
         window.requestFileSystem(LocalFileSystem.PERSISTENT, 0,onFileSystemSuccess, fail);

         /* This will check permission for storage read and write, and if got permission then 
          function send parameter will be called else if not granted then third parameter ie 
         fail function will be called */
      }

      function onFileSystemSuccess(fileSystem) 
      {
         fileSystem.root.getFile("Demo.txt",{create: true, exclusive: 
      false},gotFileEntry,fail);
        /* This will create a file with name Demo.txt in internal storage . and similarly on 
         sucessfully create it will call second parameter function i.e. gotFileEntry */
      }

      function gotFileEntry(fileEntry) {
        fileEntry.createWriter(gotFileWriter, fail);
        /* This will get a file object with path call createWriter in which 1st parameter is 
       use to write content in file and second parameter of fail to create writer */
      }

      function gotFileWriter(writer) 
      {
         writer.write(textt);/* passing parameter of the textt which is global and initialize 
       at first called function*/
          writer.onwriteend = function(evt) {
            alert("File Saved");
          }; /*This function will be called once file is written with text and saved */
       }

     function fail(error)
     {
       alert("Error","There was some problem\nError:"+error.code,"Ok");
     }
    
Share:
30,441
davidetrapani
Author by

davidetrapani

Updated on May 22, 2020

Comments

  • davidetrapani
    davidetrapani almost 4 years

    I'm having a lot of troubles saving files in Android.
    The project is a hybrid application developed with Ionic with these plugins:

    com.phonegap.plugins.fileopener 1.0.0 "File Opener"
    com.telerik.plugins.nativepagetransitions 0.4.2 "Native Page Transitions"
    cordova-plugin-compat 1.0.0 "Compat"
    cordova-plugin-crosswalk-webview 2.0.0 "Crosswalk WebView Engine"
    cordova-plugin-file 4.2.0 "File"
    cordova-plugin-network-information 1.2.2-dev "Network Information"
    cordova-plugin-whitelist 1.2.3-dev "Whitelist"
    cordova-plugin-wkwebview-engine 1.0.4-dev "Cordova WKWebView Engine"
    ionic-plugin-keyboard 2.2.1 "Keyboard"
    

    Android platform version is 5.2.1
    The device I'm using is a Samsung A7

    This is an abstract from AndroidManifest.xml

    <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    

    Case1

    if I try with this snippet (actually working on another project)

    var storagePath = "/storage/emulated/0";
    var fileDir = cordova.file.externalDataDirectory.replace(cordova.file.externalRootDirectory, '');
    var fileName = $scope.ngDocument.documentId + ".pdf"
    var filePath = storagePath + "/" + fileDir + fileName;
    $cordovaFile.writeFile(filePath, BINARY_ARR, {'append': false}).then(function(result) {}, function(err) {});

    I get {"code":5,"message":"ENCODING_ERR"} as Callback from the $cordovaFile.writeFile, no matter if I use absolute path, relative path, just the file name and no file is ever created.

    Case2

    With this snippet

    window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) {
      console.log('file system open: ' + fs.name);
      fs.root.getFile(fileName, { create: true, exclusive: false }, function (fileEntry) {
        console.log("fileEntry:" + JSON.stringify(fileEntry));
        writeFile(fileEntry, BINARY_ARR);
      }, function(data){});
    }, function(data){});

    happen two different things

    Case 2.1

    If no config options are specified in config.xml the app creates an empty folder into /storage/emulated/0/Android/media/{myAPP}

    Case 2.2

    with these two preferences

    <preference name="AndroidPersistentFileLocation" value="Compatibility" />
    <preference name="AndroidExtraFilesystems" value="cache" />
    

    a file in /storage/emulated/0 (external SSD) is created and in logcaterrors are:

    E/Vold    ( 2280): Failed to find mounted volume for /storage/extSdCard/Android/data/{myApp}/files/
    W/Vold    ( 2280): Returning OperationFailed - no handler for errno 0
    W/ContextImpl(13364): Failed to ensure directory: /storage/extSdCard/Android/data/{myApp}/files
    E/Vold    ( 2280): Failed to find mounted volume for /storage/extSdCard/Android/data/{myApp}/files/
    W/Vold    ( 2280): Returning OperationFailed - no handler for errno 0
    W/ContextImpl(13364): Failed to ensure directory: /storage/extSdCard/Android/data/{myApp}/files
    E/Vold    ( 2280): Failed to find mounted volume for /storage/extSdCard/Android/data/{myApp}/cache/
    W/Vold    ( 2280): Returning OperationFailed - no handler for errno 0
    W/ContextImpl(13364): Failed to ensure directory: /storage/extSdCard/Android/data/{myApp}/cache
    

    The strange fact is that /storage/extSdCard (symbolic link for /mnt/extSdCard) is not mounted while the external SSD is mounted on /mnt/sdcard

    Please help: I'm headbanging.
    The first snippet was working as a charm in another project. Could it be the version of ngCordova?

  • davidetrapani
    davidetrapani almost 8 years
    why should I use FileUpload when I just need to create a new file?
  • Ben Elghali Beyram
    Ben Elghali Beyram almost 8 years
    when you should use FileUpload ?
  • davidetrapani
    davidetrapani almost 8 years
    thanks for the answer and for the support. However it's OFFTOPIC. I will not downvote even though I should have to.
  • Piku
    Piku over 7 years
    Hi I am trying to save a xml file to device using your code but i am confusing with where to pass the data
  • davidetrapani
    davidetrapani over 7 years
    Data is the BINARY_ARR variabile .. as the name suggests it must be a binary array
  • Vasanth
    Vasanth over 5 years
    When I try your code, I'm getting an error named writefile.then is not a function.
  • Rvg.2ky
    Rvg.2ky over 3 years
    file transfer plugin now deprecated and dose not support android 10+