Чтение содержимого файла на стороне клиента в javascript в различных браузерах

113

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

У меня есть решение, которое работает с Firefox и Internet Explorer. Это некрасиво, но сейчас я только пробую:

function getFileContents() {
    var fileForUpload = document.forms[0].fileForUpload;
    var fileName = fileForUpload.value;

    if (fileForUpload.files) {
        var fileContents = fileForUpload.files.item(0).getAsBinary();
        document.forms[0].fileContents.innerHTML = fileContents;
    } else {
        // try the IE method
        var fileContents = ieReadFile(fileName);
        document.forms[0].fileContents.innerHTML = fileContents;
    }
}       

function ieReadFile(filename) 
{
    try
    {
        var fso  = new ActiveXObject("Scripting.FileSystemObject"); 
        var fh = fso.OpenTextFile(filename, 1); 
        var contents = fh.ReadAll(); 
        fh.Close();
        return contents;
    }
    catch (Exception)
    {
        return "Cannot open file :(";
    }
}

Я могу позвонить, getFileContents()и он запишет содержимое в fileContentsтекстовую область.

Есть ли способ сделать это в других браузерах?

На данный момент меня больше всего беспокоят Safari и Chrome, но я открыт для предложений для любого другого браузера.

Изменить: в ответ на вопрос «Почему вы хотите это сделать?»:

По сути, я хочу хэшировать содержимое файла вместе с одноразовым паролем на стороне клиента, чтобы я мог отправить эту информацию обратно в качестве проверки.

Дамовиса
источник
не то чтобы у меня есть ответ, но для ясности, вам нужно знать местонахождение файла? Если нет, нужно ли читать расположение файла из ввода файла или это может быть текстовое поле / текстовое поле / что-то еще?
Darko Z
Хороший вопрос. Нет, меня не волнует, откуда взялся файл, а только его содержимое. Использование файлового ввода кажется мне разумным, поскольку это нативный html - мне нужно сделать на одну вещь меньше.
Damovisa
почему вы вообще хотите это делать? сервер предназначен для этого.
geowa4
Хорошо, вкратце: пользователь вводит пароль и выбирает файл. Пароль хешируется вместе с содержимым файла, и он отправляется на сервер вместе с файлом. Когда он попадает туда, я могу проверить, что был использован правильный пароль клиента.
Damovisa

Ответы:

159

Отредактировано, чтобы добавить информацию о File API

Поскольку я изначально написал этот ответ, File API был предложен в качестве стандарта и реализован в большинстве браузеров ( начиная с IE 10, который добавил поддержку FileReaderAPI, описанного здесь, но еще не FileAPI). API немного сложнее, чем старый Mozilla API, поскольку он разработан для поддержки асинхронного чтения файлов, лучшей поддержки двоичных файлов и декодирования различных текстовых кодировок. В сети разработчиков Mozilla имеется некоторая документация, а также различные примеры в Интернете. Вы бы использовали его следующим образом:

var file = document.getElementById("fileForUpload").files[0];
if (file) {
    var reader = new FileReader();
    reader.readAsText(file, "UTF-8");
    reader.onload = function (evt) {
        document.getElementById("fileContents").innerHTML = evt.target.result;
    }
    reader.onerror = function (evt) {
        document.getElementById("fileContents").innerHTML = "error reading file";
    }
}

Оригинальный ответ

Похоже, что в WebKit нет способа сделать это (например, в Safari и Chrome). Единственные ключи, которые есть у объекта File, - это fileNameи fileSize. Согласно сообщению о фиксации для поддержки File и FileList, они вдохновлены объектом Mozilla File , но, похоже, поддерживают только подмножество функций.

Если вы хотите изменить это, вы всегда можете отправить патч в проект WebKit. Другой возможностью было бы предложить Mozilla API для включения в HTML 5 ; WHATWG список рассылки, вероятно, лучшее место , чтобы сделать это. Если вы это сделаете, то гораздо более вероятно, что появится кроссбраузерный способ сделать это, по крайней мере, через пару лет. Конечно, отправка патча или предложения для включения в HTML 5 действительно означает некоторую работу по защите идеи, но тот факт, что Firefox уже реализует это, дает вам кое-что для начала.

Брайан Кэмпбелл
источник
Спасибо за это - я не думаю, что на данный момент я достаточно предан делу, чтобы отправить патч. В любом случае вы, вероятно, не захотите, чтобы это произошло без вашего ведома. Это вроде как ломает песочницу браузера ...
Damovisa
4
Это не нарушает песочницу браузера, так как вы намеренно выбрали загрузку этого файла; если он может попасть на сервер, он может вернуться в браузер, только с дополнительным обходом. Учитывая работу по обеспечению работы автономного режима для веб-приложений, это было бы разумной функцией.
Брайан Кэмпбелл,
Мм, на самом деле это справедливый вопрос. Для выбора этого файла потребовалось взаимодействие с пользователем. Спасибо.
Damovisa
@Damovisa Я не знаю, заботит ли вас это по-прежнему, но я подумал, что обновлю свой ответ, упомянув новый File API, который делает то, что вы ищете, и реализован в Firefox, Chrome и ночных сборках Сафари.
Брайан Кэмпбелл
Отлично, спасибо за это. Я перешел к другой работе, но хорошо знать, что ответ есть :)
Дамовиса
25

Чтобы прочитать файл, выбранный пользователем, используя диалог открытия файла, вы можете использовать <input type="file">тег. Вы можете найти информацию об этом в MSDN . Когда файл выбран, вы можете использовать FileReader API для чтения содержимого.

function onFileLoad(elementId, event) {
    document.getElementById(elementId).innerText = event.target.result;
}

function onChooseFile(event, onLoadFileHandler) {
    if (typeof window.FileReader !== 'function')
        throw ("The file API isn't supported on this browser.");
    let input = event.target;
    if (!input)
        throw ("The browser does not properly implement the event object");
    if (!input.files)
        throw ("This browser does not support the `files` property of the file input.");
    if (!input.files[0])
        return undefined;
    let file = input.files[0];
    let fr = new FileReader();
    fr.onload = onLoadFileHandler;
    fr.readAsText(file);
}
<input type='file' onchange='onChooseFile(event, onFileLoad.bind(this, "contents"))' />
<p id="contents"></p>

cdiggins
источник
Не работает в Internet Explorer.
Merwais Muafaq,
4

Удачного кодирования!
Если вы получаете сообщение об ошибке в Internet Explorer, измените настройки безопасности, чтобы разрешить ActiveX.

var CallBackFunction = function(content)
{
    alert(content);
}
ReadFileAllBrowsers(document.getElementById("file_upload"), CallBackFunction); 

//Tested in Mozilla Firefox browser, Chrome
function ReadFileAllBrowsers(FileElement, CallBackFunction)
{
try
{
    var file = FileElement.files[0];
    var contents_ = "";

     if (file) {
        var reader = new FileReader();
        reader.readAsText(file, "UTF-8");
        reader.onload = function(evt)
        {
            CallBackFunction(evt.target.result);
        }
        reader.onerror = function (evt) {
            alert("Error reading file");
        }
    }
}
catch (Exception)
 {
    var fall_back =  ieReadFile(FileElement.value);
    if(fall_back != false)
    {
        CallBackFunction(fall_back);
    }
 }
}

///Reading files with Internet Explorer
function ieReadFile(filename)
{
 try
 {
    var fso  = new ActiveXObject("Scripting.FileSystemObject");
    var fh = fso.OpenTextFile(filename, 1);
    var contents = fh.ReadAll();
    fh.Close();
    return contents;
 }
 catch (Exception)
  {
    alert(Exception);
    return false;
  }
 }
Мникка
источник