15

I have a problem in my PhoneGap app. I would like to write a file of 15 MB. If I try the OS pulls more and more memory and the app crashes without message. I can reproduce this on android and blackberry tablets. Is there a way to implement the writing more efficient?

best regards

fe.createWriter(
(fw: any) => {
    fw.onwriteend = (e) => {
        fw.onwriteend = (e) => {
            callback();
        }
        fw.write(data);
    }

    // write BOM (dead for now)
    fw.write("");
},
(error: any) => {
    alert("FileWriter Failed: " + error.code);
});

It's TypeScript, I hope JS developers won't struggle with this ;)

4Str4ngeG4me
  • 536
  • 5
  • 18
  • Where are you writing the data to? and where is the data coming from? If you're sending a file to a server or getting a file from a server, you might want to check out [FileTransfer](http://docs.phonegap.com/en/3.0.0/cordova_file_file.md.html#FileTransfer) – Jamie Starke Sep 12 '13 at 06:14
  • The data came from a database (WebSQL) and I'd like to write them to a file on the device. It's a kind of backup mechanism. – 4Str4ngeG4me Sep 12 '13 at 09:55

2 Answers2

22

I found the answer.

Crash reason: PhoneGap FileWrite.write cannot handle too big buffer, do not know exact size, I think this issue is due to PG transfer data to iOS through URL Scheme, somehow it crash when "URL" is too long.

How to fix it: write small block every time, code below:

function gotFileWriter(writer) {
  function writeFinish() {
    // ... your done code here...
  }

  var written = 0;
  var BLOCK_SIZE = 1*1024*1024; // write 1M every time of write
  function writeNext(cbFinish) {
    var sz = Math.min(BLOCK_SIZE, data.byteLength - written);
    var sub = data.slice(written, written+sz);
    writer.write(sub);
    written += sz;
    writer.onwrite = function(evt) {
      if (written < data.byteLength)
        writeNext(cbFinish);
      else
        cbFinish();
    };
  }
  writeNext(writeFinish);
}

UPDATE Aug 12,2014:

In my practice, the performance of saving file through Cordova FileSystem is not good, especially for large file(>5M) on phone, it takes a few seconds. If you are downloading file from server to local disk, you may want a "efficient and direct" way, try cordova-plugin-file-transfer plugin.

Imskull
  • 1,316
  • 14
  • 16
  • Thank you @Imskull. It solves my same issue on Android. – duckegg Jul 16 '14 at 16:25
  • @Imskull: Thanks for the info, any link for the documentation about writing large file(>5M) – Shankar Aug 13 '14 at 15:33
  • If data is a blob you need to replace `.byteLength` with `.size`. – Sjoerd Pottuit Dec 07 '15 at 09:57
  • 2
    @lmskull Unfortunately the FileTransfer plugin does not support post data. Say you are downloading a protected file, and want to send the user login info along, to validate that. FileTransfer doesn't support that. In my case, I can't find any other solution but FileWriter – Ayman Abdel-Rahman May 26 '16 at 08:30
8

@Imskull's answer is the correct one ... i just want to put in the one for Blob (make sure it is blob and not arraybuffer) which is updated based on the one on top ... what i also added was a line to assure myself i am adding to the end of file ... it is more than enough to make ur app stop crashing (on ios mainly :P )

function gotFileWriter(writer) {
  function writeFinish() {
    // ... your done code here...
  }

  var written = 0;
  var BLOCK_SIZE = 1*1024*1024; // write 1M every time of write
  function writeNext(cbFinish) {
    writer.onwrite = function(evt) {
      if (written < data.size)
        writeNext(cbFinish);
      else
        cbFinish();
    };
    if (written) writer.seek(writer.length);
    writer.write(data.slice(written, written + Math.min(BLOCK_SIZE, data.size - written)));
    written += Math.min(BLOCK_SIZE, data.size - written);
  }
  writeNext(writeFinish);
}
Wowzaaa
  • 3,730
  • 4
  • 21
  • 23