JavaScript如何保存文件到本地?

30

已经有一种在线编写JSON文件的解决方案,但我想将JSON文件保存在本地。我尝试使用这个例子http://jsfiddle.net/RZBbY/10/创建一个下载文件的链接,使用以下调用:a.attr('href', 'data:application/x-json;base64,' + btoa(t.val())).show();有没有办法将文件保存在本地而不是提供可下载的链接?除了data:application/x-json;base64之外,还有其他类型的转换吗?

这是我的代码:

<!DOCTYPE html>
<head> 
    <meta charset="utf-8">
    <title>jQuery UI Sortable - Default functionality</title>

    <link rel="stylesheet" href="http://jqueryui.com/themes/base/jquery.ui.all.css">
    <script src="http://jqueryui.com//jquery-1.7.2.js"></script>
    <script src="http://jqueryui.com/ui/jquery.ui.core.js"></script>
    <script src="http://jqueryui.com/ui/jquery.ui.widget.js"></script>
    <script src="http://jqueryui.com/ui/jquery.ui.mouse.js"></script>
    <script src="http://jqueryui.com/ui/jquery.ui.sortable.js"></script>
        <script src="http://jqueryui.com/ui/jquery.ui.accordion.js"></script>
    <link rel="stylesheet" href="http://jqueryui.com/demos/demos.css">        
    <meta charset="utf-8">
    <style>a { font: 12px Arial; color: #ac9095; }</style>
<script type='text/javascript'>
$(document).ready(function() {
var f = $('form'), a = $('a'),
    i = $('input'), t = $('textarea');
       
$('#salva').click(function() {
    var o = {}, v = t.val();
    
    a.hide();//nasconde il contenuto
    i.each(function() { 
    o[this.name] = $(this).val(); });
    if (v === '') {
        t.val("[\n " + JSON.stringify(o) + " \n]")         
    }
    else {
        t.val(v.substr(0, v.length - 3));
        t.val(t.val() + ",\n " + JSON.stringify(o) +  " \n]")  
    }
});
});

$('#esporta').bind('click', function() {
    a.attr('href', 'data:application/x-json;base64,' + btoa(t.val())).show();
        
});
</script>
</head>
<body>
    <form>
        <label>Nome</label> <input type="text" name="nome"><br />
        <label>Cognome</label> <input type="text" name="cognome">
        <button type="button" id="salva">Salva</button>
    </form>        

    <textarea rows="10" cols="60"></textarea><br />
    <button type="button" id="esporta">Esporta dati</button>
    <a href="" style="display: none">Scarica Dati</a>
</body>
</html>
8个回答

32

1
这一直是我首选的答案。 - Jim Simson
2
在代码末尾添加 a.remove(); - RyanNerd

13

您应该检查download属性和window.URL方法,因为download属性似乎不支持data URI。这个Google的示例非常符合您的要求。


+1 我以前尝试过使用数据URI模式,它可行,但它决定了你最终得到的文件名,因此几乎没有用处。我在Mac上尝试了Firefox、Safari、Opera和Chrome,在Safari和Opera中都没有找到“BlobBuilder”。所以关于“只有Chrome dev频道(14.0.835.15+)支持此属性”的免责声明部分属实。目前它可以在FireFox上工作,在Safari和Opera上则失败。 - Shanimal
Blob Builder 在 MSIE 中也应该可以工作... http://ie.microsoft.com/testdrive/HTML5/BlobBuilder/ - Shanimal
4
链接已损坏。 - SandPiper
看起来该页面在2020年5月被删除。但是在删除前的几天仍然可以在存档中找到此处 - holem

9

在不涉及本地客户端(浏览器机器)的情况下,无法将文件保存在本地,因为这可能对客户机造成巨大威胁。您可以使用链接来下载该文件。如果您想在本地机器上存储像Json数据之类的东西,则可以使用浏览器提供的LocalStorage,即Web Storage


7
谢谢,也许它提供了错误的信息,但我以前不知道这一点,并且过去曾从中寻求帮助。请问您能告诉我这个答案中给出的链接有什么问题吗? - Adil
1
谢谢!现在我正在学习Web存储,但除了数据之外还有其他类型的转换:application/x-json;base64? - Mirko Cianfarani
1
Uao Rodneyrehm,我不知道这个网站wfools.com。 - Mirko Cianfarani

7

在Javascript中创建和保存文件的可能方法有:

使用名为FileSaver的库

saveAs(new File(["CONTENT"], "demo.txt", {type: "text/plain;charset=utf-8"}));

创建 Blob 对象并提供“另存为”选项。
var a = document.createElement("a");
a.href = window.URL.createObjectURL(new Blob(["CONTENT"], {type: "text/plain"}));
a.download = "demo.txt";
a.click();

上传数据,保存到服务器。

var data = new FormData();
data.append("upfile", new Blob(["CONTENT"], {type: "text/plain"}));
fetch("SERVER.SCRIPT", { method: "POST", body: data });

创建一个可写的文件流。
const fileHandle = await window.showSaveFilePicker();
const fileStream = await fileHandle.createWritable();
await fileStream.write(new Blob(["CONTENT"], {type: "text/plain"}));
await fileStream.close();

在NodeJS中,只需使用文件系统模块。
 require("fs").writeFile("demo.txt", "Foo bar!");

<!-- (A) LOAD FILE SAVER -->
<!-- https://cdnjs.com/libraries/FileSaver.js -->
<!-- https://github.com/eligrey/FileSaver.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script>
 
<script>
// (B) "SAVE AS"
var myFile = new File(["CONTENT"], "demo.txt", {type: "text/plain;charset=utf-8"});
saveAs(myFile);
</script>

// (A) CREATE BLOB OBJECT
var myBlob = new Blob(["CONTENT"], {type: "text/plain"});

// (B) CREATE DOWNLOAD LINK
var url = window.URL.createObjectURL(myBlob);
var anchor = document.createElement("a");
anchor.href = url;
anchor.download = "demo.txt";
    
// (C) "FORCE DOWNLOAD"
// NOTE: MAY NOT ALWAYS WORK DUE TO BROWSER SECURITY
// BETTER TO LET USERS CLICK ON THEIR OWN
anchor.click();
window.URL.revokeObjectURL(url);
document.removeChild(anchor);

    <script>
    function blobajax () {
      // (A) CREATE BLOB OBJECT
      var myBlob = new Blob(["CONTENT"], {type: "text/plain"});
    
      // (B) FORM DATA
      var data = new FormData();
      data.append("upfile", myBlob);
    
      // (C) AJAX UPLOAD TO SERVER
      fetch("3b-upload.php", {
        method: "POST",
        body: data
      })
      .then((res) => { return res.text(); })
      .then((txt) => { console.log(txt); });
    }
    </script>
    <input type="button" value="Go" onclick="blobajax()"/>

    <script>
    async function saveFile() {
      // (A) CREATE BLOB OBJECT
      var myBlob = new Blob(["CONTENT"], {type: "text/plain"});
     
      // (B) FILE HANDLER & FILE STREAM
      const fileHandle = await window.showSaveFilePicker({
        types: [{
          description: "Text file",
          accept: {"text/plain": [".txt"]}
        }]
      });
      const fileStream = await fileHandle.createWritable();
     
      // (C) WRITE FILE
      await fileStream.write(myBlob);
      await fileStream.close();
    }
    </script>
    
    <input type="button" value="Save File" onclick="saveFile()"/>

// (A) LOAD FILE SYSTEM MODULE
// https://nodejs.org/api/fs.html
const fs = require("fs");

// (B) WRITE TO FILE
fs.writeFile("demo.txt", "CONTENT", "utf8", (error, data) => {
  console.log("Write complete");
  console.log(error);
  console.log(data);
});

/* (C) READ FROM FILE
fs.readFile("demo.txt", "utf8", (error, data) => {
  console.log("Read complete");
  console.log(error);
  console.log(data);
});
*/

3

一切都取决于您想通过“本地保存”实现什么目的。您是否想允许用户下载文件?那么,<a download>是正确的选择。您是否想将其保存在本地,以便恢复应用程序状态?那么,您可能需要查看WebStorage的各种选项。具体来说,是localStorageIndexedDB。通过FilesystemAPI,您可以创建本地虚拟文件系统,可以在其中存储任意数据。


1
谢谢,但是除了数据转换之外还有其他类型的转换:application/x-json;base64? - Mirko Cianfarani
1
除了应该是“application/json”之外(参见https://dev59.com/cXRB5IYBdhLWcg3w4bKv#477819),我不知道还有什么其他合理的选择。 - rodneyrehm
1
使用IndexedDB如何将文件下载到本地? - Mirko Cianfarani
1
IndexedDB不是可下载的文件。它是浏览器内的数据库。这不是你要找的东西。 - rodneyrehm

2
因此,你的“真正”问题是:“JavaScript 如何保存到本地文件?”请看 http://www.tiddlywiki.com/。他们在内部“更改”HTML页面后将其本地保存。TiddlyWiki 的原始版本直接保存,非常好,并且保存到可配置的备份目录,时间戳作为备份文件名的一部分。TiddlyWiki 当前版本只是像任何文件下载一样下载它。您需要自行进行备份管理。:()关键是,您必须以 file:// 而不是 http:// 打开页面才能够本地保存。您浏览器的安全性不允许您将文件保存到别人的本地系统,仅允许保存到您自己的本地系统,即便如此,也不是易事。- Jesse

1
现在我正在学习Tiddlywiki,但是除了数据转换之外还有其他类型的转换:data:application/x-json;base64? - Mirko Cianfarani
TiddlyWiki 使用 Java Applet 访问本地文件系统,而不是 JavaScript。 - st-boost
3
TiddlyWiki 使用 Java applet 来支持 Safari 和 Opera 浏览器。对于 IE 浏览器,它使用 ActiveX,在 Firefox/Camino 浏览器中,它使用纯 JavaScript(通过 privilegeManager)或者一个 Firefox 扩展程序(自从 privilegeManager 在 v15 中被移除后)。 - dwurf
这个 jQuery 插件是从 TiddlyWiki 中提取出来的,它的工作方式就像 @dwurf 解释的那样。http://jquery.tiddlywiki.org/twFile.html - mahemoff

2

使用这个方法可以把所有内容都保存在头部和正文标签中吗? - Ray S.

0

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