代码之家  ›  专栏  ›  技术社区  ›  Toji

使用html5/javascript生成和保存文件

  •  289
  • Toji  · 技术社区  · 14 年前

    我最近一直在摆弄WebGL,让一个collada阅读器工作。问题是速度非常慢(collada是一种非常冗长的格式),所以我将开始将文件转换为更易于使用的格式(可能是json)。问题是,我已经有了用JavaScript解析文件的代码,所以我也可以将它作为导出程序使用!问题是保存。

    现在,我知道我可以解析文件,将结果发送到服务器,并让浏览器以下载的形式从服务器请求返回文件。但是事实上,服务器与这个特定的过程没有任何关系,那么为什么要让它参与进来呢?我的内存中已经有了所需文件的内容。有没有什么方法可以让用户使用纯javascript进行下载?(我对此表示怀疑,但不妨问一下……)

    而且要清楚:我不是在没有用户知识的情况下尝试访问文件系统!用户将提供一个文件(可能通过拖放),脚本将在内存中转换该文件,并提示用户下载结果。就浏览器而言,所有这些都应该是“安全”的活动。

    [编辑]: 我没有提前提过,所以回答“flash”的海报就足够有效了,但我所做的部分工作是试图强调纯HTML5可以做什么……所以在我的情况下,闪光是直接的。(尽管对于任何一个做“真正的”网络应用的人来说,这是一个完全正确的答案。)在这种情况下,除非我想让服务器参与进来,否则看起来我运气不好。不管怎样,还是谢谢你!

    15 回复  |  直到 6 年前
        1
  •  244
  •   Cedric Reichenbach    9 年前

    好的,创建一个数据:由于马修和丹尼克斯特指出了这个选项,Uri绝对为我做了这个技巧!以下是我的基本方法:

    1)将所有内容放入一个称为“内容”的字符串中(例如,通过最初在其中创建内容或通过读取已构建页面的标记的innerhtml)。

    2)建立数据URI:

    uriContent = "data:application/octet-stream," + encodeURIComponent(content);
    

    根据浏览器类型等,会有长度限制,但例如,火狐3.6.12至少在256K之前都可以工作。用base64编码而不是使用encodeuricomponent可能会提高效率,但对我来说没问题。

    3)打开一个新窗口并将其“重定向”到此URI,提示您输入我的javascript生成页面的下载位置:

    newWindow = window.open(uriContent, 'neuesDokument');
    

    就是这样。

        2
  •  254
  •   OrangeDog    9 年前

    HTML5浏览器的简单解决方案…

    function download(filename, text) {
        var pom = document.createElement('a');
        pom.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
        pom.setAttribute('download', filename);
    
        if (document.createEvent) {
            var event = document.createEvent('MouseEvents');
            event.initEvent('click', true, true);
            pom.dispatchEvent(event);
        }
        else {
            pom.click();
        }
    }
    

    用法

    download('test.txt', 'Hello world!');
    
        3
  •  78
  •   Eli Grey    10 年前

    HTML5定义了 window.saveAs(blob, filename) 方法。现在没有任何浏览器支持它。但是有一个兼容性库叫做 FileSaver.js 这将此功能添加到大多数现代浏览器(包括Internet Explorer 10+)。Internet Explorer 10支持 navigator.msSaveBlob(blob, filename) 方法( MSDN ,在filesaver.js中用于Internet Explorer支持。

    我写了一篇 blog posting 有关此问题的详细信息。

        4
  •  42
  •   Steve Eynon Henning    6 年前

    保存大文件

    长数据URI会给浏览器带来性能问题。另一个保存客户端生成的文件的选项是将其内容放在blob(或文件)对象中,并使用 URL.createObjectURL(blob) . 这将返回一个可用于检索blob内容的URL。blob存储在浏览器中,直到 URL.revokeObjectURL() 对URL或创建该URL的文档调用时,它将关闭。大多数Web浏览器都有 support for object URLs 只有Opera Mini不支持。

    强制下载

    如果数据是文本或图像,浏览器可以打开文件,而不是将其保存到磁盘。若要在单击链接时下载文件,可以使用 download 属性。然而,并非所有的Web浏览器都有 support for the download attribute . 另一个选择是使用 application/octet-stream 作为文件的mime类型,但这会导致文件显示为二进制blob,如果不指定或不能指定文件名,则用户尤其不友好。也见 Force to open "Save As..." popup open at text link click for pdf in HTML '.

    指定文件名

    如果blob是使用文件构造函数创建的,您也可以设置文件名,但只有少数Web浏览器(包括Chrome&firefox)具有 support for the File constructor . 也可以将文件名指定为 下载 属性,但这取决于 security considerations . Internet Explorer 10和11提供了自己的方法, msSaveBlob ,以指定文件名。

    示例代码

    var file;
    var data = [];
    data.push("This is a test\n");
    data.push("Of creating a file\n");
    data.push("In a browser\n");
    var properties = {type: 'text/plain'}; // Specify the file's mime-type.
    try {
      // Specify the filename using the File constructor, but ...
      file = new File(data, "file.txt", properties);
    } catch (e) {
      // ... fall back to the Blob constructor if that isn't supported.
      file = new Blob(data, properties);
    }
    var url = URL.createObjectURL(file);
    document.getElementById('link').href = url;
    <a id="link" target="_blank" download="file.txt">Download</a>
        5
  •  32
  •   Yassir Ennazk    11 年前
    function download(content, filename, contentType)
    {
        if(!contentType) contentType = 'application/octet-stream';
            var a = document.createElement('a');
            var blob = new Blob([content], {'type':contentType});
            a.href = window.URL.createObjectURL(blob);
            a.download = filename;
            a.click();
    }
    
        6
  •  25
  •   Pekka    13 年前

    看看道格·内纳的 Downloadify 这是一个基于flash的javascript接口。

    下载是一个很小的javascript+flash库,它可以在浏览器中即时生成和保存文件,而无需服务器交互。

        7
  •  16
  •   T.Todua    6 年前

    简单的解决方案!

    <a download="My-FileName.txt" href="data:application/octet-stream,HELLO-WORLDDDDDDDD">Click here</a>

    适用于所有现代浏览器。

        8
  •  10
  •   Matthew Flaschen    14 年前

    您可以生成 data URI . 但是,存在特定于浏览器的限制。

        9
  •  10
  •   Razakhel    10 年前

    我使用了filesaver( https://github.com/eligrey/FileSaver.js )而且效果很好。
    例如,我执行了这个函数来导出显示在页面上的日志。
    你必须传递一个数组来声明blob,所以我可能写得不正确,但它对我有用。
    以防万一,小心替换:这是使这个全局化的语法,否则它将只替换他遇到的第一个语法。

    exportLogs : function(){
        var array = new Array();
    
        var str = $('#logs').html();
        array[0] = str.replace(/<br>/g, '\n\t');
    
        var blob = new Blob(array, {type: "text/plain;charset=utf-8"});
        saveAs(blob, "example.log");
    }
    
        10
  •  8
  •   maikel    10 年前

    我发现有两种简单的方法对我有用。首先,使用已单击的 a 元素并插入下载数据。第二,生成 具有下载数据的元素,执行 a.click() 然后再把它取下来。但第二种方法只有在用户单击操作也调用时才起作用。(部分)浏览器块 click() 来自其他上下文,如加载或超时后触发(setTimeout)。

    <!DOCTYPE HTML>
    <html>
      <head>
        <meta charset="UTF-8">
        <script type="text/javascript">
          function linkDownload(a, filename, content) {
            contentType =  'data:application/octet-stream,';
            uriContent = contentType + encodeURIComponent(content);
            a.setAttribute('href', uriContent);
            a.setAttribute('download', filename);
          }
          function download(filename, content) {
            var a = document.createElement('a');
            linkDownload(a, filename, content);
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
          }
        </script>
       </head>
      <body>
        <a href="#" onclick="linkDownload(this, 'test.txt', 'Hello World!');">download</a>
        <button onclick="download('test.txt', 'Hello World!');">download</button>
      </body>
    </html>
    
        11
  •  6
  •   Dennkster    14 年前

    这里有一个链接,指向Mathew建议的data-uri方法,它在Safari上有效,但不太好,因为我无法设置文件类型,它被保存为“未知”,然后我必须稍后再次转到那里并更改它以查看文件…

    http://www.nihilogic.dk/labs/canvas2image/

        12
  •  4
  •   Jeanine    14 年前

    您可以使用localstorage。这是HTML5相当于cookies。它似乎可以在Chrome和Firefox上使用,但在Firefox上,我需要将其上传到服务器上。也就是说,直接在家里的电脑上测试没有用。

    我正在研究HTML5示例。去 http://faculty.purchase.edu/jeanine.meyer/html5/html5explain.html 滚动到迷宫一号。重建迷宫的信息是使用localstorage存储的。

    我在本文中寻找用于加载和处理XML文件的HTML5 JavaScript。它与旧的HTML和JavaScript相同吗?????

        13
  •  3
  •   Kevin    8 年前

    如前所述 File API,以及 FileWriter FileSystem API可用于从浏览器选项卡/窗口的上下文存储客户机上的文件。

    但是,对于后两个API,您应该注意以下几点:

    • API的实现目前仅存在于基于Chromium的浏览器中(Chrome&Opera)
    • 这两个API都在2014年4月24日从W3C标准轨道上脱离,到目前为止都是专有的。
    • 将来有可能从实现浏览器中删除(现在是专有的)API。
    • 沙箱 (磁盘上文件不能产生效果的位置)用于存储用API创建的文件。
    • 虚拟文件系统 (不一定存在于磁盘上的目录结构与从浏览器中访问时的目录结构形式相同)表示用API创建的文件。

    下面是一些简单的示例,说明如何直接和间接地串联使用API来实现这一点:

    BakedGoods *

    bakedGoods.get({
            data: ["testFile"],
            storageTypes: ["fileSystem"],
            options: {fileSystem:{storageType: Window.PERSISTENT}},
            complete: function(resultDataObj, byStorageTypeErrorObj){}
    });
    

    使用原始文件、文件编写器和文件系统API

    function onQuotaRequestSuccess(grantedQuota)
    {
    
        function saveFile(directoryEntry)
        {
    
            function createFileWriter(fileEntry)
            {
    
                function write(fileWriter)
                {
                    var dataBlob = new Blob(["Hello world!"], {type: "text/plain"});
                    fileWriter.write(dataBlob);              
                }
    
                fileEntry.createWriter(write);
            }
    
            directoryEntry.getFile(
                "testFile", 
                {create: true, exclusive: true},
                createFileWriter
            );
        }
    
        requestFileSystem(Window.PERSISTENT, grantedQuota, saveFile);
    }
    
    var desiredQuota = 1024 * 1024 * 1024;
    var quotaManagementObj = navigator.webkitPersistentStorage;
    quotaManagementObj.requestQuota(desiredQuota, onQuotaRequestSuccess);
    

    尽管文件系统和文件编写器API不再在标准轨道上,但在我看来,它们的使用在某些情况下是合理的,因为:

    • 联合国执行浏览器供应商的新兴趣可能会使他们重新回到它上面。
    • 实现(基于Chromium)浏览器的市场渗透率很高
    • 谷歌(Chromium的主要贡献者)尚未向API提供生命周期结束日期。

    然而,“一些案例”是否包含你自己的,是由你来决定的。

    *Bakedgoods是由这里的人维护的:)

        14
  •  1
  •   Stephen Rauch ajay singh koranga    6 年前

    这个线程对于了解如何生成二进制文件和提示下载命名文件非常有价值,所有这些都是在没有服务器的客户机代码中完成的。

    对于我来说,第一步是从保存的数据生成二进制blob。对于一个二进制类型,有很多这样的示例,在我的例子中,我有一个具有多个类型的二进制格式,可以作为数组传递来创建blob。

    saveAnimation: function() {
    
        var device = this.Device;
        var maxRow = ChromaAnimation.getMaxRow(device);
        var maxColumn = ChromaAnimation.getMaxColumn(device);
        var frames = this.Frames;
        var frameCount = frames.length;
    
        var writeArrays = [];
    
    
        var writeArray = new Uint32Array(1);
        var version = 1;
        writeArray[0] = version;
        writeArrays.push(writeArray.buffer);
        //console.log('version:', version);
    
    
        var writeArray = new Uint8Array(1);
        var deviceType = this.DeviceType;
        writeArray[0] = deviceType;
        writeArrays.push(writeArray.buffer);
        //console.log('deviceType:', deviceType);
    
    
        var writeArray = new Uint8Array(1);
        writeArray[0] = device;
        writeArrays.push(writeArray.buffer);
        //console.log('device:', device);
    
    
        var writeArray = new Uint32Array(1);
        writeArray[0] = frameCount;
        writeArrays.push(writeArray.buffer);
        //console.log('frameCount:', frameCount);
    
        for (var index = 0; index < frameCount; ++index) {
    
          var frame = frames[index];
    
          var writeArray = new Float32Array(1);
          var duration = frame.Duration;
          if (duration < 0.033) {
            duration = 0.033;
          }
          writeArray[0] = duration;
          writeArrays.push(writeArray.buffer);
    
          //console.log('Frame', index, 'duration', duration);
    
          var writeArray = new Uint32Array(maxRow * maxColumn);
          for (var i = 0; i < maxRow; ++i) {
            for (var j = 0; j < maxColumn; ++j) {
              var color = frame.Colors[i][j];
              writeArray[i * maxColumn + j] = color;
            }
          }
          writeArrays.push(writeArray.buffer);
        }
    
        var blob = new Blob(writeArrays, {type: 'application/octet-stream'});
    
        return blob;
    }
    

    下一步是让浏览器提示用户下载具有预定义名称的blob。

    我只需要在HTML5中添加一个命名链接,我可以重用它来重命名初始文件名。我把它藏起来了,因为链接不需要显示。

    <a id="lnkDownload" style="display: none" download="client.chroma" href="" target="_blank"></a>
    

    最后一步是提示用户下载文件。

    var data = animation.saveAnimation();
    var uriContent = URL.createObjectURL(data);
    var lnkDownload = document.getElementById('lnkDownload');
    lnkDownload.download = 'theDefaultFileName.extension';
    lnkDownload.href = uriContent;
    lnkDownload.click();
    
        15
  •  0
  •   Ilyas karim    7 年前

    以下是将文件导出为zip的教程:

    在开始之前,有一个要保存文件的库,库的名称是filesaver.js,您可以在这里找到这个库。现在,让我们开始,包括所需的库:

    <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.4/jszip.min.js"  type="text/javascript"></script>
    <script type="text/javascript" src="https://fastcdn.org/FileSaver.js/1.1.20151003/FileSaver.js" ></script>
    

    现在复制此代码,此代码将下载一个zip文件,其中包含hello.txt文件的内容是hello world。如果一切正常,这将下载一个文件。

    <script type="text/javascript">
        var zip = new JSZip();
        zip.file("Hello.txt", "Hello World\n");
        zip.generateAsync({type:"blob"})
        .then(function(content) {
            // see FileSaver.js
            saveAs(content, "file.zip");
        });
    </script>
    

    这将下载一个名为file.zip的文件。您可以在此处阅读更多信息: http://www.wapgee.com/story/248/guide-to-create-zip-files-using-javascript-by-using-jszip-library