javascript - 在 JavaScript 中使用本地文件作为数据源

标签 javascript html file filereader

背景:

我想制作一个使用JavaScript/HTML 的“应用程序”,并且可以由浏览器直接从文件系统打开。此应用必须能够从另一个文件读取数据。然后我将使用 JS 来解析它并呈现页面。作为一个简化的例子,假设我有一个 CSV 文件 (download here) :

Mark Rodgers,mark.rodgers@company.com,Accounting
[...]
Melissa Jones,melissa@company.com,CEO

我希望能够使用 JS 读取文件并使用其中的数据生成我的页面。

到目前为止我取得的成就:

Demo (右键单击 ->“另存为”将 HTML 保存到您的计算机)。它也可以在 jsfiddle 上找到以半损坏的方式(布局损坏,但它在功能上应该仍然是正确的)。

只需将 CSV 文本文件拖放到拖放框中,或使用文件菜单选择文本文件,JavaScript 将读取、解析文件并填充表格。

这依赖于 FileReader API;大部分繁重的工作都是由这个函数完成的:

function handleFileSelect(evt) {
    evt.stopPropagation();
    evt.preventDefault();

    var files = evt.target.files || evt.dataTransfer.files; // FileList object.
    var file = files[0];

    // this creates the FileReader and reads stuff as text
    var fr = new FileReader();
    fr.onload = parse;
    fr.readAsText(file);

    // this is the function that actually parses the file
    // and populates the table
    function parse()
    {
        var table = document.getElementById('emps');
        var employees = fr.result.split('\n'); var c = 0;
        for (var i in employees)
        {
            var employee = employees[i].split(',');
            if (employee.length == 3)
            {
                var row = document.createElement('tr');
                row.innerHTML = "<td>" + employee.join("</td><td>") + "</td>";
                table.appendChild(row);
                c++;
            }
        }
        document.getElementById('result').innerHTML = '<span>Added ' + c + ' employees from file: ' + file.name + '</span>';
    }
}

几乎没问题,但它给用户手动加载文件带来了不便。理想情况下,它应该能够自动加载它,但出于安全原因,还没有浏览器允许这样做……。

解决方案要求:

  • 必须离线工作;即:它不能依赖任何在线服务。这也包括在本地计算机上运行的 HTTP 服务器。这个想法是让它在任何只安装了浏览器的计算机上运行。

  • 必须在使用 file:/// 协议(protocol)(即:硬盘驱动器上的 HTML 页面)打开页面时工作。

  • 不应依赖第三方插件(例如:Flash、Java、shudders ActiveX)。我很确定如果页面位于 file:///

  • 中,这些可能无论如何都无法工作
  • 它必须能够接受任意数据。这排除了以准备好使用的良好格式加载文件的可能性 像 JSON。

  • 如果它可以在 Firefox 或 Chrome 中的任何一个(最好是两者)上运行,那就没问题。依赖实验性 API 也是可以的

我事先知道文件名是什么,所以它可以在 HTML 本身中编码。 任何使我能够从磁盘读取文件的解决方案都很好,它不必使用 FileReader API。

因此,如果有一个聪明的 hack 可以将文件加载到页面中,那也很好(也许将它加载到一个不可见的 iframe 中并让 JS 检索内容);没关系。

最佳答案

这是我用于 Firefox 的代码,它不可可移植,但有效:

正如 OP 评论的那样,enablePrivilege() 已被弃用,这应该被认为是可用的。但是由于我的 Firefox 使用以前的配置文件仍然可以使用我的代码,所以我深入研究了 prefs.js(因为 about:config 隐藏了这些设置,)在这里是您需要的设置才能正常工作。

user_pref("capability.principal.codebase.p0.granted", "UniversalXPConnect");
user_pref("capability.principal.codebase.p0.id", "file://");  // path to the html file.
user_pref("capability.principal.codebase.p0.subjectName", "");

代码如下:

var File = function(file) {
  netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
  var ios = Components.classes["@mozilla.org/network/io-service;1"]
                            .getService(Components.interfaces.nsIIOService);
  if (!File.baseURI) {
    File.baseURI = ios.newURI(location.href.substring(0, location.href.lastIndexOf('/')+1), null, null);
    File.baseFolder = File.baseURI.QueryInterface(Components.interfaces.nsIFileURL).file.path;
  }
  var URL = ios.newURI(file, null, File.baseURI);
  this.fptr = URL.QueryInterface(Components.interfaces.nsIFileURL).file;
}

File.prototype = {
  write: function(data) {
    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
    var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
                             .createInstance(Components.interfaces.nsIFileOutputStream);
    foStream.init(this.fptr, 0x02 | 0x08 | 0x20, 0666, 0);
    var converter = Components.classes["@mozilla.org/intl/converter-output-stream;1"]
                              .createInstance(Components.interfaces.nsIConverterOutputStream);
    converter.init(foStream, null, 0, 0);
    converter.writeString(data);
    converter.close();
  },
  read: function() {
    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
    var fstream = Components.classes["@mozilla.org/network/file-input-stream;1"]
                            .createInstance(Components.interfaces.nsIFileInputStream);
    var cstream = Components.classes["@mozilla.org/intl/converter-input-stream;1"]
                            .createInstance(Components.interfaces.nsIConverterInputStream);
    fstream.init(this.fptr, -1, 0, 0);
    cstream.init(fstream, null, 0, 0);
    var data = "";
    // let (str = {}) { // use this only when using javascript 1.8
    var str = {};
      cstream.readString(0xffffffff, str);
      data = str.value;
    // }
    cstream.close();
    return data;
  }
};

关于javascript - 在 JavaScript 中使用本地文件作为数据源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13428532/

相关文章:

javascript - 使用 jQuery 进行表单验证(无需validation.js)

javascript - JavaScript 可以访问 &lt;script src =""> 元素的源代码吗?

c++ - 我在哪里可以获得文件 libstdc++.so.6.0.15 的拷贝

php - 将 php 代码实现为 html 或仅使用 php 会更快吗?查看更多详情

html - 导航栏下的图像

python - 将文本文件拆分为带有特殊分隔符行的部分 - python

ios - 多点连接 : Share Files to all peers simultaneously

asp.net - 返回 404 错误的脚本文件

javascript - jquery中var数据的格式化

javascript - 从 Javascript 对象中获取某些东西的方法更快