Подтвердить что ты не робот

Использование локального файла в качестве источника данных в JavaScript

Фон:

Я хочу создать "приложение", которое использует только JavaScript/HTML и может быть открыто браузером непосредственно из файловой системы. Это приложение должно иметь возможность читать данные из другого файла. Затем я буду использовать JS для анализа и отображения страниц. В качестве упрощенного примера предположим, что у меня есть файл CSV (скачать здесь):

Mark Rodgers,[email protected],Accounting
[...]
Melissa Jones,[email protected],CEO

Я хочу, чтобы иметь возможность читать файл с помощью JS и использовать в нем данные для создания моей страницы.

Что я сделал до сих пор:

Demo (щелкните правой кнопкой мыши → "Сохранить как", чтобы сохранить HTML на свой компьютер). Он также доступен на jsfiddle в полуразрушенном режиме (макет разбит, но он все равно должен быть функционально корректным).

Просто перетащите текстовый файл CSV в поле перетаскивания или выберите текстовый файл, используя меню файла, и JavaScript прочитает, проанализирует файл и заполнит таблицу.

Это зависит от API FileReader; большая часть тяжелого подъема выполняется с помощью этой функции:

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, дрожит ActiveX). Я уверен, что они, вероятно, не сработают, если страница находится в file:///

  • Он должен иметь возможность принимать произвольные данные. Это исключает загрузку файла в хорошо организованном формате, который готов к использованию как JSON.

  • Если он работает на обоих (идеально оба) Firefox или Chrome, это прекрасно. Это также ОК, чтобы полагаться на экспериментальные API

Я знаю, что имя файла заблаговременно, поэтому оно может быть закодировано в самом HTML. Любое решение, которое позволяет мне читать файл с диска, отлично, ему не нужно использовать API FileReader.

Итак, если есть умный взлом для загрузки файла на страницу, которая тоже очень хороша (возможно, загрузите его в невидимый iframe и получите JS-содержимое); это тоже ОК.

4b9b3361

Ответ 1

Вот код, который я использовал для Firefox, который не переносится, но works:

Как прокомментировал 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;
  }
};

Ответ 2

Вот пример, который использует данные JSON во внешнем файле, который работает локально или на сервере. Этот пример просто использует настройку языка браузера для загрузки <script> с локализованным html, а затем обрабатывает свой json-объект до reset данных в указанных тегах с локализованным контентом

<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."}
];

но вы можете использовать любой параметр для условной загрузки соответствующего файла (он будет вставлен в качестве первого тега в <head> , поэтому он будет использоваться в любом месте), а формат 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 очень удобен - это будет что-то вроде: (untested 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 в файле://из коробки и хрома (возможно, другие браузеры, основанные на веб-сайтах) могут быть настроены для его разрешения. Зная, что он НЕ МОЖЕТ РАБОТАТЬ на IE < 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 (кроме запуска небольшого веб-сервера), отредактируйте его.

Изменить 2:

В браузерах mozilla вы также можете использовать iframes

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

Ответ 3

Предполагая, что файл csv находится в том же каталоге, что и приложение, я должен загрузить файл с помощью AJAX. Насколько я знаю, можно получить файл в текстовом формате, а затем проанализировать его. Это должно работать в IE и Firefox, но не работает в Chrome (если только вы не запускаете хром с настройкой командной строки --allow-file-access-from-files).

Ответ 4

Насколько я понимаю, содержимое файла полностью находится под вашим контролем, и оно не обязательно должно быть конкретным форматом? Вам нужен только способ читать?

Вы можете объявить глобальную функцию "handleFile". В вашем внешнем файле содержимое должно быть таким:

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

Чтобы "прочитать" файл, просто добавьте элемент script с соответствующим атрибутом src. В вашей функции "handleFile" вы получаете свое содержимое.

Расположение файла, вероятно, должно быть предварительно задано пользователем, но после этого вы можете сохранить местоположение в localStorage или что-то в этом роде.

Ответ 5

Убедитесь, что файл находится в том же каталоге или в подкаталоге, загрузите файл с помощью AJAX.

В отличие от тега script, вы получите доступ к содержимому.

Ответ 6

Это можно сделать довольно легко, используя класс 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" );