背景:
我想创建一个仅使用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:///
协议(即:硬盘驱动器上的HTML页面)打开页面时必须正常工作。
不是否应依赖第三方添加(例如:Flash,Java, shudders ActiveX)。如果页面位于file:///
必须能够接受任意数据。这排除了以易于使用的良好格式加载文件 像JSON。
如果它适用于(理想情况下)Firefox或Chrome两者都可以。依靠实验性API
我事先知道文件名是什么,因此它可以在HTML本身中编码。 使我能够从磁盘读取文件的任何解决方案都很好,它不必使用FileReader API。
因此,如果有一个聪明的黑客将文件加载到一个页面也很好(可能将其加载到一个不可见的iframe并让JS检索内容);那也没关系。
答案 0 :(得分:4)
以下是我用于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;
}
};
答案 1 :(得分:4)
以下是在本地或服务器上运行的外部文件中使用JSON数据的示例。此示例仅使用浏览器的语言设置来加载&lt;脚本&gt;使用本地化的html,然后处理其json对象以使用本地化内容重置指示标记中的数据
<html><meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<head>
<script>
function setLang(){
for (var i=0;i<items.length;i++){
term=document.getElementById(items[i].id)
if (term) term.innerHTML=items[i].value
}
}
var lang=navigator.userLanguage || navigator.language;
var script=document.createElement("script");
script.src=document.URL+"-"+lang.substring(0,2)+".js"
var head = document.getElementsByTagName('head')[0]
head.insertBefore(script,head.firstChild)
</script>
</head>
<body onload='setLang()'>
<div id="string1" class="txt">This is the default text of string1.</div>
<div id="string2" class="txt">This is the default text of string2.</div>
</body></html>
此处的数据文件如下所示:
items=[
{"id":"string1","value":"Localized text of string1."},
{"id":"string2", "value":"Localized text of string2."}
];
但您可以使用任何参数来有条件地加载相应的文件(它将作为&lt; head&gt;中的第一个标记插入,因此它可以在任何地方使用)并且JSON格式能够处理大量的文件数据的。你可能想要将函数setLang重命名为更合适的东西并修改它以满足你的需要,例如...为每个我添加一行,然后添加带有数据的字段(看起来你已经有了该部分的句柄)你的JSON看起来像是:
items=[
{"fname":"john","lname":"smith","address":"1 1st St","phone":"555-1212"},
{"fname":"jane","lname":"smith","address":"1 1st St","phone":"555-1212"}
];
如果您需要预处理数据,awk非常方便 - 它将类似于:(未经测试的猜测)
awk 'BEGIN{FS=",";print "items=[\n"}
{printf "{\"fname\":\"%s\",\"lname\":\"smith\",\"address\":\"1 1st St\",\"phone\":\"555-1212\"},\n", $1, $2, $3, $4}
END{print "];"}' file.csv > file.js
编辑:现在OP更清晰,只有mozilla浏览器允许在文件上开启XMLHttpRequest://开箱即用,并且chrome(可能是其他基于webkit的浏览器)可以配置为允许它。知道它可以 NOT 在IE&lt; 10上工作,你可以:
var filePath = "your_file.txt";
xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET",filePath,false);
xmlhttp.overrideMimeType('text/plain');
xmlhttp.send(null);
//maybe check status !=404 here
var fileContent = xmlhttp.responseText;
var fileArray = fileContent.split('\n')
var n = fileArray.length;
//process your data from here probably using split again for ','
我正在为可能有类似问题的其他人留下最初的json-p变体,但可以控制他们的数据格式,因为它适用于所有支持javascript的浏览器。但是,如果有人知道如何让它适用于IE(除了运行小型Web服务器),请编辑。
编辑2:
使用mozilla浏览器,您还可以使用iframe
<html>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<head>
<script>
function showContents(frameObject){
alert(frameObject.contentDocument.body.innerHTML);
//replace with your code
}
</script>
</head>
<body onload='showContents()'>
<iframe id="frametest" src="data.txt" onload="showContents(this);"
style="visibility:hidden;display:none"></iframe>
</body></html>
答案 2 :(得分:3)
假设csv文件与应用程序位于同一目录中,我将使用AJAX加载该文件。据我所知,可以以文本格式获取文件,然后解析它。这应该适用于IE和Firefox,但在Chrome中不起作用(除非使用--allow-file-access-from-files
命令行设置运行chrome)。
答案 3 :(得分:1)
据我了解,该文件的内容完全由您控制,并且不必是特定的格式? 你只需要一种阅读方式吗?
您可以声明一个全局函数“handleFile”。 在您的外部文件中,内容必须如下:
handleFile('Mark Rodgers,mark.rodgers@company.com,Accounting');
要“读取”该文件,只需添加一个带有相应src属性的脚本元素即可。 在你的函数“handleFile”中,你可以得到你的内容。
文件的位置可能最初必须由用户设置,但之后您可以将该位置保存在localStorage或类似的位置。
答案 4 :(得分:1)
确保文件位于同一目录或子目录中,使用AJAX加载文件。
与脚本标记不同,您可以访问内容。
答案 5 :(得分:1)
这可以使用javascript XMLHttpRequest()类轻松完成:
function FileHelper()
{}
{
FileHelper.readStringFromFileAtPath = function(pathOfFileToReadFrom)
{
var request = new XMLHttpRequest();
request.open("GET", pathOfFileToReadFrom, false);
request.send(null);
var returnValue = request.responseText;
return returnValue;
}
}
...
var text = FileHelper.readStringFromFileAtPath ( "mytext.txt" );