Как загрузить и сохранить файл с помощью phonegap/cordova на Android

Я на исходе. Я постараюсь быть кратким. Использование Cordova/Phonegap 3.0 (и получить те же результаты на 2.8.0). Андроид версии 4.0.4. Код работает на BlackBerry10 (Q10 и Z10).

На Android выдает ошибку JSON Error (нет, я не разбираю JSON, похоже, это вылезло из недр кордовы). В конце я вставлю объект ошибки JSON.stringified.

Итак, перейдем к коду: сначала функция успеха файловой системы:

function onFSSuccess(fileSystem) {
if (fileSystem == null) {
    window.alert("fileSystem is null");
}
var root = fileSystem.root; 
root.getDirectory("com.app.id",{create:true},gotDir,onError);};

Затем функция для обработки успешного поиска каталога:

function gotDir(d){
    DATADIR = d;        
    doTheDl (d.fullPath + "/update.sql",fileTransfer);
};

Затем фактический вызов для получения файловой системы:

window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, onFSSuccess, null);

Затем функция для загрузки файла:

function doTheDl (localPath,fileTransfer) {
    try {
        window.alert ("Downloading to '" + localPath + "'");
        fileTransfer.download (
            uri,
            localPath,
            function (entry) {
                try {
                    $("#dbDownloadProgressContainer").text("File saved to " + entry.name + ". Applying script to database...");
                    dbInitObj.applyUpdateScript(entry); 
                }
                catch (e) {
                    window.alert ( e);
                }

            },
            function (err) {
                window.alert ("ERROROR!!! - " + err);
                var errCodeName = err.code;
                switch (err.code) {
                    case FileTransferError.FILE_NOT_FOUND_ERR:
                        errCodeName ='FILE_NOT_FOUND_ERR';
                        break;
                    case FileTransferError.INVALID_URL_ERR:
                        errCodeName="INVALID_URL_ERR";
                        break;
                    case FileTransferError.CONNECTION_ERR:
                        errCodeName="CONNECTION_ERR";
                        break;
                    case FileTransferError.ABORT_ERR:
                        errCodeName="ABORT_ERR";
                        break;
                    default:
                        errCodeName = "UNKNOWN";
                        break;                      
                }
                window.alert ("Download failed: " + err.source + ", " + err.target + ", " + errCodeName);
            },
            true                
        );

    }
    catch (e) {
        window.alert ( e);
    }
}

Чувак, мне нравятся все эти асинхронные обратные вызовы... Далее мы переходим к сути дела, пытаясь ПРОЧИТАТЬ загруженный файл:

//Bulk of applyUpdateScript script ommited, but eventually it gets here:

function readComplete (evt) {

    $("#dbDownloadProgressContainer").text("Parsing script file...");

    //Got this gem from here: http://beckism.com/2010/09/splitting-lines-javascript/
    var lines = evt.target.result.match(/^.*([\n\r]+|$)/gm);


    //var lineIndx = lines.length;

    window.setTimeout(function () {
            $("#dbDownloadProgressContainer").text("Processing " + lines.length + " statements");
},50);
};  

try {
        var fileReader = new FileReader();
        fileReader.onloadend=readComplete;

        fileReader.onerror=function (err) {
            //var errStr = translateFileError (err);
            window.alert ("FileReader.onerror: " +JSON.stringify (err));
        };


        fileReader.onloadstart=function (evt) {
            window.alert ("FileReader.onloadstart - " + JSON.stringify (evt));
        };


        fileReader.onload=function (evt)
        {
            window.alert ("FileReader.onload - Called when the read has successfully completed.- " + JSON.stringify (evt));
        };


        fileReader.onprogress = function (evt)
        {
            window.alert ("FileReader.onprogress - " + JSON.stringify (evt));
        }

        fileReader.onabort = function (evt)
        {
            window.alert ("FileReader.onabort - " + JSON.stringify (evt));
        }


        function gotFile (fileEntry) {
            window.alert ("Activating reader for file '" + fileEntry.fullPath + "'");
            fileReader.readAsText(fileEntry);

        };

        function noFileFound (fileError) {
            alert ("Can not access database update script: code " + translateFileError (fileError));
        };

        // window.alert ("scriptPath.name = " + scriptPath.name);

        DATADIR.getFile (scriptPath.name,null,gotFile,noFileFound);
    }
    catch (e) {
        window.alert (e);
}

ТЕПЕРЬ, когда я нажимаю биты чтения, я в конечном итоге получаю это из события onerror (помните, что это объект ошибки JSON.stringfied:

{
   "type":"error",
   "bubbles":false,
   "cancelBubble":false,
   "cancelable":false,
   "lengthComputable":false,
   "loaded":0,
   "total":0,
   "target":{
      "_readyState":2,
      "_error":{
         "code":"JSON error"
      },
      "_result":null,
      "_fileName":"file:///mnt/sdcard/com.app.id/update.sql",
      "_realReader":{
         "error":null,
         "result":"",
         "readyState":0
      }
   }
}

Также обратите внимание, что «com.app.id» является заполнителем для фактического идентификатора приложения — его нельзя вставить, опасаясь конфиденциальных имен. Я пробовал и другие имена папок. Другие примечательные (?) предметы:

  • Событие прогресса загрузки, по-видимому, указывает на то, что мы загружаем ровно вдвое больше фактического размера файла (wtf?)
  • Результаты одинаковы на устройстве Android и эмуляторе
  • BlackBerry10 работает нормально

Заранее спасибо умным людям....


person demaniak    schedule 05.08.2013    source источник
comment
Так совпало, что console.log, который я добавил, чтобы зафиксировать ошибку выше, попал именно на строку 666. Так что, может быть, я должен просто бросить это, как одержимый демоном, и пойти открыть бар на пляже в Мозамбике.   -  person demaniak    schedule 05.08.2013
comment
Хорошо, надо было проверить это раньше, но в любом случае, кажется, что файл загружается на SDCard правильно, так что это означает, что что-то идет грушевидным только с чтением. Может ограничение по размеру? Размер рассматриваемого файла составляет около 12 МБ....   -  person demaniak    schedule 05.08.2013
comment
ОК, проверил, что это НЕ размер, то же самое происходит с файлом размером 18 КБ.   -  person demaniak    schedule 05.08.2013


Ответы (1)


ХОРОШО. Это было решение:

    function gotFile (fileEntry) {
        fileEntry.file (function (file) {
        fileReader.readAsText(file);
    });
};

Так что огромное спасибо этому чуваку: http://www.html5rocks.com/en/tutorials/file/filesystem/?ModPagespeed=noscript

В случае, если вы пропустили это, волшебство заключается в вызове функции "file(...)" для объекта fileEntry. Почему это работает на BB10 БЕЗ этого....ааааааааа

person demaniak    schedule 05.08.2013
comment
К сведению: в конце концов я столкнулся с проблемой размера при чтении файла размером 24 МБ (который должен быть 12 МБ). Обойти эту проблему, сбросив все вышеуказанное решение и реализовав подход частичной загрузки и обработки с заголовком HTTP Range. - person demaniak; 06.08.2013