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

Nul*_*ion 29 javascript html5 file filereader

背景:

我想创建一个使用JavaScript/HTML的"app",可以直接从文件系统通过浏览器打开.此应用必须能够从其他文件中读取数据.然后我将使用JS来解析它并呈现页面.作为一个简化的例子,假设我有一个CSV文件(在这里下载):

Mark Rodgers,mark.rodgers@company.com,Accounting
[...]
Melissa Jones,melissa@company.com,CEO
Run Code Online (Sandbox Code Playgroud)

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

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

演示(右键单击 - >"另存为"将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>';
    }
}
Run Code Online (Sandbox Code Playgroud)

几乎没问题,但是用户不方便手动加载文件.理想情况下,它应该能够自动加载它,但出于安全考虑,没有浏览器会允许它......

解决方案要求

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

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

  • 如果依靠第三方附加功能(如:闪光,爪哇,颤抖的ActiveX).我很确定如果页面在,这些可能无论如何都行不通file:///

  • 它必须能够接受任意数据.这排除了以一种良好的格式加载文件,可以像JSON一样使用.

  • 如果它适用于(理想情况下)Firefox或Chrome两者都可以.依靠实验API也是可以的

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

因此,如果有一个聪明的黑客将文件加载到一个页面也很好(可能将其加载到一个不可见的iframe并让JS检索内容); 那也没关系.

xia*_*oyi 4

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

正如OP评论的那样,enablePrivilege()已被弃用,这应该被认为是可用的。但由于我的 Firefox 使用以前的配置文件仍然可以使用我的代码,因此我深入研究了一些prefs.jsabout: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", "");
Run Code Online (Sandbox Code Playgroud)

代码如下:

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;
  }
};
Run Code Online (Sandbox Code Playgroud)