2014-10-15 1 views
9

В моем приложении «Кордова» я загружаю произвольные файлы, такие как изображения или видеофайлы. Это делается с помощью плагина переноса файлов Cordova и заголовка «Range», потому что мне нужно загрузить файлы по частям.Слияние нескольких частей файла в Кордове

Моя проблема заключается в том, что я хочу объединить несколько небольших «байт» -файлов обратно в исходный файл, когда-то, где использовать этот файл. Каждый раз, когда я пытаюсь прочитать полученные части как binaryString через FileReader и записывать их вместе в новый файл, этот файл оказывается намного больше, чем части исходного файла altogther, и полученный файл неприменим.

Любая помощь приветствуется.

Вот мой код до сих пор (долго и некрасиво):

document.addEventListener('deviceready', deviceready, false); 

var App; 

var finishedFileUrl = ""; 

var async = { 
    sequence: function(items, callback) {  
     var def = $.Deferred(), 
     deferrers = [$.Deferred()]; 

     for(var i = 0; i < items.length; i++) { 
      (function (n) {  
       deferrers[n + 1] = $.Deferred(); 
       deferrers[n].always(function() { 
        callback(items[n], deferrers[n + 1]); 
       }); 
      })(i); 
     } 
     deferrers[items.length].always(function() { 
      def.resolve(); 
     });   
     deferrers[0].resolve(); 

     return def.promise(); 
    } 
} 

var aSmallImageArray = [ 
'' // Put URL to JPG accessible with Range Header Request here 
]; 

var aByteSizeImageArray = []; 

function formatDownloadArray(fileSize) { 
    for(var j = 1000; j <= fileSize; j += 1000) { 
     aByteSizeImageArray.push(j); 
    } 
    aByteSizeImageArray.push(j); 
} 

function deviceready() { 
    console.log('dv ready'); 

    function registerHandlers() { 
     App = new DownloadApp(); 
     formatDownloadArray(XXXXX);  // XXXXX should be size of JPG in bytes 
     document.getElementById("startDl").onclick = function() { 
      var that = this; 
      console.log("load button clicked"); 
      var folderName = "testimagefolder"; 

      // sequence call 
      async.sequence(aByteSizeImageArray, function(currentBytes, iter) { 
       var filePath = aSmallImageArray[0]; 
       var fileName = aSmallImageArray[0].substr(52,99) + currentBytes; 
       console.log(filePath); 
       console.log(fileName); 
       console.log("Starting with: " + fileName); 
       var uri = encodeURI(filePath); 
       var folderName = "testimagefolder"; 
       document.getElementById("statusPlace").innerHTML = "<br/>Loading: " + uri; 
       App.load(currentBytes, uri, folderName, fileName, 
        function progress (percentage) { 
         document.getElementById("statusPlace").innerHTML = "<br/>" + percentage + "%"; 
        }, 
        function success (entry) { 
         console.log("Entry: " + entry); 
         document.getElementById("statusPlace").innerHTML = "<br/>Image saved to: " + App.filedir; 
         console.log("DownloadApp.filedir: " + App.filedir); 
         iter.resolve(); 
        }, 
        function error() { 
         document.getElementById("statusPlace").innerHTML = "<br/>Failed load image: " + uri; 
         iter.resolve(); 
        } 
       );    
      }).then(function afterAsync() { 
       console.log("ASYNC DONE"); 
       var ohNoItFailed = function ohNoItFailed (exeperro) { 
        console.log(exeperro); 
       } 
       // now we merge the fileparts into one file to show it 
       window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (FileSystem) { 
        FileSystem.root.getDirectory(folderName, {create: true, exclusive: false}, function itSuccessed (Directory) { 
         Directory.getFile(aSmallImageArray[0].substr(52,99), {create: true, exclusive: false}, function itSuccessedAgain (fileEntry) { 
          finishedFileUrl = fileEntry.toURL(); 
          var directoryReader = Directory.createReader(); 
          var allFiles = directoryReader.readEntries(function succesReadDir (fileEntries) { 
           async.sequence(fileEntries, function(currentFile, iterThis) { 
            currentFile.file(function (theActualFile) { 
             var myFileReader = new FileReader(); 
             myFileReader.onload = function (content) { 
              console.log('FileReader onload event fired!'); 
              console.log('File Content should be: ' + content.target.result); 
              fileEntry.createWriter(
              function mergeImage (writer) { 
               writer.onwrite = function (evnt) { 
                console.log("Writing successful!"); 
                iterThis.resolve(); 
               } 
               writer.seek(writer.length); 
               writer.write(content.target.result); 
              }, ohNoItFailed); 
             }; 
             myFileReader.readAsBinaryString(theActualFile); 
            }, ohNoItFailed); 
           }).then(function afterAsyncTwo() { 
            console.log("NOW THE IMAGE SHOULD BE TAKEN FROM THIS PATH: " + finishedFileUrl); 

            //window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (FileSystem) { 
             //FileSystem.root.getDirectory(folderName, {create: true, exclusive: false}, function itSuccessed (Directory) { 
              //Directory.getFile(aSmallImageArray[0].substr(52,99), {create: true, exclusive: false}, function  itSuccessedAgain (fileEntry) {  
               //fileEntry.createWriter( 

             document.getElementById("image_here").src = finishedFileUrl;  
           });  
          }, ohNoItFailed);        
         }, ohNoItFailed);  
        }, ohNoItFailed);  
       }, ohNoItFailed);      
      });  
     };  
    }  
    registerHandlers();  
}  

var DownloadApp = function() {} 

DownloadApp.prototype = { 
    filedir: "", 
    load: function(currentBytes, uri, folderName, fileName, progress, success, fail) { 
     var that = this; 
     that.progress = progress; 
     that.success = success; 
     that.fail = fail; 
     filePath = ""; 

     that.getFilesystem(
       function(fileSystem) { 
        console.log("GotFS"); 
        that.getFolder(fileSystem, folderName, function(folder) { 
         filePath = folder.toURL() + fileName; 
         console.log("FILEPATH: " + filePath); 
         console.log("URI: " + uri); 
         that.transferFile(currentBytes, uri, filePath, progress, success, fail); 
        }, function(error) { 
         console.log("Failed to get folder: " + error.code); 
         typeof that.fail === 'function' && that.fail(error); 
        }); 
       }, 
       function(error) { 
        console.log("Failed to get filesystem: " + error.code); 
        typeof that.fail === 'function' && that.fail(error); 
       } 
     ); 
    }, 

    getFilesystem: function (success, fail) { 
     window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem; 
     window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, success, fail); 
    }, 

    getFolder: function (fileSystem, folderName, success, fail) { 
     fileSystem.root.getDirectory(folderName, {create: true, exclusive: false}, success, fail) 
    }, 

    transferFile: function (currentBytes, uri, filePath, progress, success, fail) { 
     var that = this; 
     that.progress = progress; 
     that.success = success; 
     that.fail = fail; 
     console.log("here we go"); 
     console.log("filePath before Request: " + filePath); 

     var previousBytes = currentBytes - 1000; 

     var transfer = new FileTransfer(); 
     transfer.onprogress = function(progressEvent) { 
      if (progressEvent.lengthComputable) { 
       var perc = Math.floor(progressEvent.loaded/progressEvent.total * 100); 
       typeof that.progress === 'function' && that.progress(perc); // progression on scale 0..100 (percentage) as number 
      } else { 
      } 
     }; 

     transfer.download(
      uri, 
      filePath, 
      function success (entry) { 
       console.log("File saved to: " + entry.toURL()); 
       typeof that.success === 'function' && that.success(entry); 
      }, 
      function errorProblem(error) { 
       console.log("An error has occurred: Code = " + error.code); 
       console.log("download error source " + error.source); 
       console.log("download error target " + error.target); 
       console.log("download error code " + error.code); 
       typeof that.fail === 'function' && that.fail(error); 
      }, 
      true, 
      { 
       headers: { 
        "Range": "bytes=" + previousBytes + "-" + currentBytes 
       } 
      } 
     ); 
    } 
} 

асинхронной код на StackOverflow пользователем: Paul Facklam -> Большое спасибо!

+0

Не могли бы вы добавить дополнительные сведения и комментарии коментариев? Похоже, вы пытаетесь загрузить файл по 1000 байт за раз, но есть несколько магических чисел, которые не ясны ('1000',' 52', '99'). Если ваши результирующие части собираются больше, чем ожидалось, возможно ли, что вы написали файл как ASCII/chars вместо двоичных данных? Вы забыли пропустить заголовки ответов? Предложение: попробуйте загрузить файл с небольшим размером, который содержит только пару штук, и используйте шестнадцатеричный редактор для сравнения сохраненных частей с исходным файлом с сервера. Черт, попробуйте файл с открытым текстом. – nothingisnecessary

+0

«Магические числа» используются для извлечения имени файла из первого элемента в массиве (52,99), 1000, как вы правильно предположили, соответствует 1000 байтам, которые я хочу загрузить. Я уже пробовал с меньшим файлом, и если я смотрю на содержимое, они, конечно, не бинарные, а байт-коды. Я могу опубликовать пример части этого файла, если это поможет. – plocks

ответ

1

Использование readAsArrayBuffer() вместо readAsBinaryString() сделал трюк!

Таким образом, вместо:

myFileReader.readAsBinaryString(theActualFile); 

я сделал:

myFileReader.readAsBinaryArray(theActualFile); 

И файл результирующего изображения может использоваться.

1

вы можете построить blob из других blobs, как те, которые вы используете FileReader. (File() s являются Blobs)

// put three blobs into a fourth: 
var b=new Blob([new Blob(["hello"]), new Blob([" "]), new Blob(["world"])]); 

// verify the blob has the data we expect: 
var fr=new FileReader(); 
fr.onload=function(){alert(this.result);}; 
fr.readAsBinaryString(b); // shows: "hello world" 

binaryString аромат используется здесь, чтобы показать, как эти строки низкого порядка складывают, но действительно новый экземпляр блоб должен иметь все ориг (произвольный) байт от оригинала blobs, даже если они не состоят из простых строк ...

+0

Я собираюсь проверить это. Благодарю. – plocks

+0

Хорошо, я протестировал его, и это не работает для меня. Он по-прежнему не создает файл изображения, который можно просмотреть. – plocks

+0

@DevanLoper: не видя обновленного кода, я не могу сказать, почему он не работает, но я убедился, что двоичные данные могут быть измельчены и повторно собраны с использованием вышеуказанного подхода: http://jsfiddle.net/ox0rgmvc/ 1/ – dandavis