HTML5文件API从服务器下载文件并将其保存在沙盒中

28

我正在尝试理解HTML5 API。 我正在设计一个Web应用程序,其中浏览器客户端需要从服务器下载多个文件;用户将对已下载的文件执行某些操作,然后应用程序需要将状态保存在用户硬盘上。我知道浏览器只能将这些文件保存到其沙盒中,只要用户可以在第二次启动应用程序时检索这些文件,这就很好了。 我应该使用BlobBuilder还是FileSaver?我有点迷惑。

3个回答

67

我将向您展示如何使用XMLHttpRequest Level 2下载文件,并使用FileSystem APIFileSaver接口保存它们。

##下载文件##

要下载文件,您将使用XMLHttpRequest Level 2(也称为XHR2),它支持跨域请求、上传进度事件以及二进制数据的上传/下载。在文章“XMLHttpRequest2中的新技巧”中有很多使用XHR2的示例。

要将文件下载为blob,您需要将responseType指定为“blob”。 您还可以使用类型“text”,“arraybuffer”或“document”。 下面的函数下载位于url中的文件并将其发送到success回调:

function downloadFile(url, success) {
    var xhr = new XMLHttpRequest(); 
    xhr.open('GET', url, true); 
    xhr.responseType = "blob";
    xhr.onreadystatechange = function () { 
        if (xhr.readyState == 4) {
            if (success) success(xhr.response);
        }
    };
    xhr.send(null);
}
success回调将会接收一个Blob实例作为参数,它可以稍后被修改并保存和/或上传到服务器。

##使用文件系统API保存文件##

正如Can i use...网站指出的那样,支持FileSystem API的浏览器不多。对于Firefox,有一个解释缺乏支持的原因。所以你需要使用Chrome来完成这个任务。

首先,你需要请求存储空间,可以是临时的或永久的。你可能想要一个永久的存储空间,在这种情况下,你需要提前请求存储空间的配额(一些事实):

window.requestFileSystem  = window.requestFileSystem || window.webkitRequestFileSystem;
window.storageInfo = window.storageInfo || window.webkitStorageInfo;

// Request access to the file system
var fileSystem = null         // DOMFileSystem instance
    , fsType = PERSISTENT       // PERSISTENT vs. TEMPORARY storage 
    , fsSize = 10 * 1024 * 1024 // size (bytes) of needed space 
;
    
window.storageInfo.requestQuota(fsType, fsSize, function(gb) {
    window.requestFileSystem(fsType, gb, function(fs) {
        fileSystem = fs;
    }, errorHandler);
}, errorHandler);

现在您已经可以访问文件系统,可以在其中保存和读取文件。以下函数可以将blob保存到指定路径中的文件系统中:

function saveFile(data, path) {
    if (!fileSystem) return;
    
    fileSystem.root.getFile(path, {create: true}, function(fileEntry) {
        fileEntry.createWriter(function(writer) {
            writer.write(data);
        }, errorHandler);
    }, errorHandler);
}

通过文件路径读取文件:

function readFile(path, success) {
    fileSystem.root.getFile(path, {}, function(fileEntry) {
        fileEntry.file(function(file) {
            var reader = new FileReader();

            reader.onloadend = function(e) {
                if (success) success(this.result);
            };

            reader.readAsText(file);
        }, errorHandler);
    }, errorHandler);
}

除了 readAsText 方法外,根据 FileReader API,您还可以调用 readAsArrayBufferreadAsDataURL

##使用 FileSaver##

文章“在客户端保存生成的文件”很好地解释了此API的用法。某些浏览器可能需要FileSaver.js才能具有saveAs接口。

如果您与 downloadFile 函数一起使用,可能会得到类似以下的内容:

downloadFile('image.png', function(blob) {
    saveAs(blob, "image.png");
});

当然,如果用户能够可视化图片、操作它,然后将其保存在他的驱动器中,那会更有意义。

###错误处理器###

只是为了满足这个例子:

function errorHandler(e) {
    var msg = '';

    switch (e.code) {
        case FileError.QUOTA_EXCEEDED_ERR:
            msg = 'QUOTA_EXCEEDED_ERR';
            break;
        case FileError.NOT_FOUND_ERR:
            msg = 'NOT_FOUND_ERR';
            break;
        case FileError.SECURITY_ERR:
            msg = 'SECURITY_ERR';
            break;
        case FileError.INVALID_MODIFICATION_ERR:
            msg = 'INVALID_MODIFICATION_ERR';
            break;
        case FileError.INVALID_STATE_ERR:
            msg = 'INVALID_STATE_ERR';
            break;
        default:
            msg = 'Unknown Error';
            break;
    };

    console.log('Error: ' + msg);
}

##有用的链接##


谢谢,我特别想知道这个难题的前半部分。XHR2有大小限制吗? - Mamadum

2

值得注意的是,截至今日,Safari仍不支持此属性...(也不支持IE11) https://caniuse.com/#search=download - Cody G

1
我的技巧是简单地附加具有指向您多个下载的“src”属性的IFRAME。服务器站点应该使用“disposition: attachment”标头发送文件,然后客户端将尝试将文件存储在本地。唯一的“问题”是IFRAME将作为残留物留在您的DOM树中,直到用户离开或重新加载页面。使IFRAME不可见(例如width=0; height=0;),你就可以开始了!所有浏览器。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接