【问题标题】:FileReader() fails to read large filesFileReader() 无法读取大文件
【发布时间】:2019-12-13 07:38:45
【问题描述】:

我正在尝试使用此应用脚本将文件上传到 Google Drive,它适用于较小的文件,但在上传大于约 1 GB + 的文件时失败

我一加载大文件,就会执行 onerror 函数。我无法弄清楚如何在切片中读取文件。 这是我的代码。任何帮助将不胜感激。

const chunkSize = 5242880;
$('#uploadfile').on("change", function() {
    var file = this.files[0];
    if (file.name != "") {
        var fr = new FileReader();
        fr.fileName = file.name;
        fr.fileSize = file.size;
        fr.fileType = file.type;
        fr.onload = init;
        fr.readAsArrayBuffer(file);
    }
});
function init() {
    $("#progress").text("Initializing.");
    var fileName = this.fileName;
    var fileSize = this.fileSize;
    var fileType = this.fileType;
    console.log({fileName: fileName, fileSize: fileSize, fileType: fileType});
    var buf = this.result;
    var chunkpot = getChunkpot(chunkSize, fileSize);
    var uint8Array = new Uint8Array(buf);
    var chunks = chunkpot.chunks.map(function(e) {
        return {
            data: uint8Array.slice(e.startByte, e.endByte + 1),
            length: e.numByte,
            range: "bytes " + e.startByte + "-" + e.endByte + "/" + chunkpot.total,
        };
    });
    google.script.run.withSuccessHandler(function(at) {
        var xhr = new XMLHttpRequest();
        xhr.open("POST", "https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable");
        xhr.setRequestHeader('Authorization', "Bearer " + at);
        xhr.setRequestHeader('Content-Type', "application/json");
        xhr.send(JSON.stringify({
            mimeType: fileType,
            name: fileName,
        }));
        xhr.onload = function() {
            doUpload({
                location: xhr.getResponseHeader("location"),
                chunks: chunks,
            });
        };
        xhr.onerror = function() {
            console.log(xhr.response);
        };
    }).getAt();
}
function doUpload(e) {
    var chunks = e.chunks;
    var location = e.location;
    var cnt = 0;
    var end = chunks.length;
    var temp = function callback(cnt) {
        var e = chunks[cnt];
        var xhr = new XMLHttpRequest();
        xhr.open("PUT", location, true);
        xhr.setRequestHeader('Content-Range', e.range);
        xhr.send(e.data);
        xhr.onloadend = function() {
            var status = xhr.status;
            cnt += 1;
            console.log("Uploading: " + status + " (" + cnt + " / " + end + ")");
            $("#progress").text("Uploading: " + Math.floor(100 * cnt / end) + "%");
            if (status == 308) {
                callback(cnt);
            } else if (status == 200) {
                $("#progress").text("Done.");
            } else {
                $("#progress").text("Error: " + xhr.response);
            }
        };
    }(cnt);
}
function getChunkpot(chunkSize, fileSize) {
    var chunkPot = {};
    chunkPot.total = fileSize;
    chunkPot.chunks = [];
    if (fileSize > chunkSize) {
        var numE = chunkSize;
        var endS = function(f, n) {
            var c = f % n;
            if (c == 0) {
                return 0;
            } else {
                return c;
            }
        }(fileSize, numE);
        var repeat = Math.floor(fileSize / numE);
        for (var i = 0; i <= repeat; i++) {
            var startAddress = i * numE;
            var c = {};
            c.startByte = startAddress;
            if (i < repeat) {
                c.endByte = startAddress + numE - 1;
                c.numByte = numE;
                chunkPot.chunks.push(c);
            } else if (i == repeat && endS > 0) {
                c.endByte = startAddress + endS - 1;
                c.numByte = endS;
                chunkPot.chunks.push(c);
            }
        }
    } else {
        var chunk = {
            startByte: 0,
            endByte: fileSize - 1,
            numByte: fileSize,
        };
        chunkPot.chunks.push(chunk);
    }
    return chunkPot;
}

【问题讨论】:

  • 这些文件继承的 Blob 接口上有一个slice() 方法。虽然我不太清楚你为什么需要阅读它?您不能按原样发送文件吗?
  • 不包括 fr.readAsArrayBuffer(file);上传不起作用。
  • 如果这行得通,你为什么不想使用它?
  • 它不适用于大文件..仅适用于小文件。
  • 如果您传递 Blob/File 或 ArrayBuffer,请求应该是相同的,所以我不明白为什么它会因文件而失败,当然除非您没有正确执行.

标签: jquery google-apps-script google-drive-api filereader


【解决方案1】:

大文件失败,因为您在处理之前读取内存中的整个文件。

File 对象是 Blob 的一个实例,它具有 .slice 方法来创建文件的小视图。

您可以只调用 readAsArrayBuffer 函数来获得更小的文件切片。

例如。你需要编写一个函数,你将在其中使用一些块大小

var chunk = 1024;
var offset = 0;
var fr = new FileReader();
fr.onload = function() {
        var view = new Uint8Array(fr.result);
        for (var i = 0; i < view.length; ++i) {
            if (view[i] === 10 || view[i] === 13) {
                // Check if \r or \n found
                // column length = offset + position of \r or \n
                callback(offset + i);
                return;
            }
        }
        // continue reading slices if \r or \n not found.
        offset += chunk;
        continue_reading();
    };
    fr.onerror = function() {
        // Something went wrong
        callback(0);
    };
    continue_reading();

    function continue_reading() {
        if (offset >= file.size) {
            // If no \r or \n found. The column size is equal to the full
            // file size
            callback(file.size);
            return;
        }
        var slice = file.slice(offset, offset + chunk);
        fr.readAsArrayBuffer(slice);
    }

请注意,这些说明是在假设输入为 ASCII 的情况下进行的。

【讨论】:

  • 我无法将您的答案放在我的上下文中。你能帮我解决这个问题吗?谢谢
  • 那么,告诉我你面临的问题是什么。
  • 我无法在 onload (int) 上调用 readAsArrayBuffer 函数,因为文件上传不会在 onChange 函数上执行 readAsArrayBuffer() 的情况下执行
  • 那么你的问题是什么时候调用“function init()”函数来上传文件?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-21
  • 1970-01-01
  • 2022-10-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多