【问题标题】:Merging multiple parts of a file in Cordova在 Cordova 中合并文件的多个部分
【发布时间】:2014-12-10 18:06:53
【问题描述】:

在我的 Cordova 应用程序中,我正在下载任意文件,例如图像或视频文件。这是通过 Cordova 文件传输插件和“Range”标头完成的,因为我需要分批下载文件。

我的问题是,我想将几​​个小的“字节”文件合并回原来的文件中,他们曾经在哪里使用该文件。每次我尝试通过 FileReader 将生成的部分读取为 binaryString 并将它们一起写入一个新文件时,该文件最终会比原始文件的部分大得多,并且生成的文件无法使用。

感谢任何帮助。

这是我到目前为止的代码(又长又丑):

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 -> 非常感谢!

【问题讨论】:

  • 您能否添加更多详细信息和代码 cmets?看起来您正在尝试一次加载 1000 个字节的文件,但其中有一些不清楚的幻数(10005299)。如果您生成的片段组装得比预期的要大,您是否可以将文件写回为 ASCII/chars 而不是二进制数据?您是否忘记省略响应标头? (如果有的话;不确定) 建议:尝试下载一个只有几个片段的小文件,并使用十六进制编辑器将保存的片段与服务器上的原始文件进行比较。哎呀,尝试使用纯文本文件。
  • “幻数”用于从数组的第一个元素 (52,99) 中提取文件名,正如您正确假设的那样,1000 对应于我要下载的 1000 字节部分.我已经尝试过使用较小的文件,如果我查看内容,它们肯定不是二进制的,而是字节码字符。如果有帮助,我可以发布该文件的一个示例。

标签: javascript file cordova concatenation file-transfer


【解决方案1】:

您可以从其他 blob 构建 blob,例如您现在使用 FileReader 的 blob。 (File()s 是 Blob)

// 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 风格来显示这些低阶字符串如何堆叠,但实际的新 blob 实例应该具有来自原始 blob 的所有原始(任意)字节,即使它们不是由简单字符串组成的...

【讨论】:

  • 我要测试一下。谢谢。
  • 好的,我已经测试过了,它对我不起作用。它仍然无法生成可见的图像文件。
  • @DevanLoper:没有看到您更新的代码,我无法说明为什么它不起作用,但我确实验证了二进制数据可以使用上述方法进行分割和重新组装:jsfiddle.net/ox0rgmvc/1
  • 我会尽快更新我的代码。感谢您的反馈。
【解决方案2】:

使用 readAsArrayBuffer() 而不是 readAsBinaryString() 成功了!

所以而不是:

myFileReader.readAsBinaryString(theActualFile);

我做到了:

myFileReader.readAsBinaryArray(theActualFile);

并且生成的图像文件是可用的。

【讨论】:

    猜你喜欢
    • 2016-11-26
    • 1970-01-01
    • 2023-01-04
    • 2013-12-04
    • 2011-10-01
    • 1970-01-01
    • 2016-05-27
    • 2021-03-10
    • 2015-12-27
    相关资源
    最近更新 更多