2012-11-17 58 views
29

背景:使用本地文件作爲JavaScript中的數據源

我要特別強調使用JavaScript/HTML 只有,並且可以通過瀏覽器直接從文件系統中開設了一個「應用程序」。這個應用程序必須能夠從另一個文件讀取數據。然後我將使用JS來解析它並呈現頁面。作爲一個簡單的例子,假設我有一個CSV文件(download here)

Mark Rodgers,[email protected],Accounting 
[...] 
Melissa Jones,[email protected],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>'; 
    } 
} 

這是幾乎 OK,但不方便用戶進入手動加載文件。理想情況下,它應該能夠自動加載它,但出於安全原因,沒有瀏覽器會允許... ...。

解決方案的需求:

  • 必須脫機工作;即:它不能依賴任何在線服務。這也包括在本地機器上運行的HTTP服務器。這個想法是隻在安裝了瀏覽器的情況下在任何計算機上運行。

  • 當使用file:///協議(即:硬盤上的HTML頁面)打開頁面時必須工作。

  • 應該依靠第三方附加功能(如:閃光,爪哇,發抖的ActiveX)。我很確定這些可能不會工作,如果頁面是file:///

  • 它必須能夠接受任意數據。這就排除了以一種行爲良好的格式加載文件,該文件已準備好像JSON一樣用於消費 。

  • 如果它在任何一個(理想情況下都是)Firefox或Chrome上都可以使用,那很好。也可以依靠實驗API

我知道文件名是什麼,所以它可以在HTML本身編碼。任何解決方案,使我能夠從磁盤讀取文件是好的,它不必使用FileReader API。所以如果有一個聰明的黑客文件加載到一個頁面也可以(也許加載到一個不可見的iframe,並有JS檢索內容);這也沒關係。

+2

在Chrome中,你應該以允許訪問指定命令行參數'--allow-文件訪問從-files' 'file://'方案。由於安全考慮,我不確定Chrome會以任何其他更方便的方式執行此操作。 – Stan

+3

+1

不確定,但node-webkit項目可能會讓您感興趣。 https://github.com/rogerwang/node-webkit –

回答

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; 
    } 
}; 
+0

'File()'採取什麼參數? – NullUserException

+0

@NullUserException相對於當前文件的文件路徑。像'var file = new File('xxx.csv');' – xiaoyi

+0

嗯Firefox在這一行上窒息:'let(str = {}){' – NullUserException

1

據我瞭解,該文件的內容完全是你的控制之下,它並沒有成爲一個特定的格式? 你只需要一種閱讀方式?

你可以聲明一個全局函數「handleFile」。 在外部文件中的內容必須是這樣的:

handleFile('Mark Rodgers,[email protected],Accounting'); 

「讀」的文件,只需添加腳本元素與相應的src屬性。 在你的函數「handleFile」中,你得到了你的內容。

該文件的位置可能最初必須由用戶設置,但在此之後,您可以將位置保存在localStorage或類似的東西。

+0

遺憾的是,該文件的格式*不受我控制。 – NullUserException

4

以下是在本地或服務器上使用的外部文件中使用JSON數據的示例。這個例子只是使用瀏覽器的語言設置加載< SCRIPT>與本地化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."} 
]; 

但可以使用任何參數有條件地加載適當的文件(它將在<頭被插入作爲第一標籤>,所以這將是在任何地方使用)和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是非常方便的 - 這將是這樣的:(未經測試guestimate)

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的瀏覽器)可以被配置爲允許它。知道它可能在IE < 10 NOT工作,您可以:

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> 
+1

我很抱歉,但我無法控制這些文件的格式,也不能以任何方式對它們進行預處理,然後再將它們加載到JS中。否則我不會問這個問題,因爲這是簡單的方法。它必須能夠處理**任意**數據 – NullUserException

+0

實際上,這不是一個JSON文件,而是一個JSONP腳本。 – Bergi

+0

是真的,我只是說它是一個包含json數據的文件,因爲我不想暗示它需要一個json-p樣式的回調函數包裝器。它基本上是一個include文件,它可以包含變量,函數等......但是由於OP更新了格式被固定爲csv,所以XMLHttpRequest實際上是唯一的方法,並且不是可移植的,除非有一些hack才能獲得innerHTML 「外部」腳本...... iframe方法只能在默認情況下在mozilla瀏覽器中運行 – technosaurus

1

確保該文件在同一目錄或子目錄,加載與AJAX的文件。

與腳本標記不同,您將可以訪問內容。

3

假設csv文件與應用程序位於同一目錄中,我將使用AJAX加載文件。據我所知,可以用文本格式獲取文件,然後解析它。這應該在IE和Firefox中工作,但在Chrome中不起作用(除非通過--allow-file-access-from-files命令行設置運行chrome)。

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"); 
相關問題