Odczytywanie zawartości plików po stronie klienta w javascript w różnych przeglądarkach

113

Próbuję udostępnić tylko skryptowe rozwiązanie do odczytywania zawartości pliku na komputerze klienckim za pośrednictwem przeglądarki.

Mam rozwiązanie, które działa z przeglądarkami Firefox i Internet Explorer. To nie jest ładne, ale w tej chwili tylko próbuję:

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 :(";
    }
}

Mogę zadzwonić getFileContents()i zapisze zawartość w polu fileContentstekstowym.

Czy można to zrobić w innych przeglądarkach?

W tej chwili najbardziej interesują mnie Safari i Chrome, ale jestem otwarty na sugestie dotyczące innych przeglądarek.

Edycja: w odpowiedzi na pytanie „Dlaczego chcesz to zrobić?”:

Zasadniczo chcę zhaszować zawartość pliku wraz z jednorazowym hasłem po stronie klienta, aby móc odesłać te informacje jako weryfikację.

Damovisa
źródło
nie to, że mam odpowiedź, ale dla jasności, czy musisz znać lokalizację pliku? Jeśli nie, czy lokalizacja pliku musi być odczytana z wejścia pliku, czy może to być pole tekstowe / obszar tekstowy / cokolwiek?
Darko Z
Dobre pytanie. Nie, nie obchodzi mnie, skąd pochodzi plik, tylko jego zawartość. Używanie pliku wejściowego wydaje mi się rozsądne, ponieważ jest to natywny html - muszę zrobić o jedną rzecz mniej.
Damovisa
dlaczego w ogóle chcesz to zrobić? serwer jest do tego przeznaczony.
geowa4
Ok, w skrócie: użytkownik wprowadza hasło i wybiera plik. Hasło zostaje zaszyfrowane wraz z zawartością pliku i zostaje wysłane na serwer wraz z plikiem. Kiedy to nastąpi, mogę sprawdzić, czy użyto prawidłowego hasła klienta.
Damovisa,

Odpowiedzi:

159

Edytowano, aby dodać informacje o interfejsie File API

Ponieważ pierwotnie napisałem tę odpowiedź, API File zostało zaproponowane jako standard i zaimplementowane w większości przeglądarek (od IE 10, która dodała obsługę FileReaderopisanego tutaj API, choć jeszcze nie FileAPI). API jest nieco bardziej skomplikowane niż starsze API Mozilli, ponieważ zostało zaprojektowane do obsługi asynchronicznego odczytu plików, lepszej obsługi plików binarnych i dekodowania różnych kodowań tekstu. W sieci Mozilla Developer Network dostępna jest pewna dokumentacja, a także różne przykłady w Internecie. Użyłbyś go w następujący sposób:

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

Oryginalna odpowiedź

Wygląda na to, że nie ma na to sposobu w WebKit (a więc w Safari i Chrome). Jedyne klucze, które ma obiekt File , to fileNamei fileSize. Zgodnie z komunikatem zatwierdzenia dla obsługi File i FileList, są one inspirowane obiektem File Mozilli , ale wydaje się, że obsługują tylko podzbiór funkcji.

Jeśli chcesz to zmienić, zawsze możesz wysłać poprawkę do projektu WebKit. Inną możliwością byłoby zaproponowanie API Mozilli do włączenia do HTML 5 ; WHATWG lista dyskusyjna jest prawdopodobnie najlepszym miejscem, aby to zrobić. Jeśli to zrobisz, jest znacznie bardziej prawdopodobne, że będzie można to zrobić za pomocą różnych przeglądarek, przynajmniej za kilka lat. Oczywiście przesłanie poprawki lub propozycji włączenia do HTML 5 oznacza trochę pracy w obronie pomysłu, ale fakt, że Firefox już go implementuje, daje ci od czego zacząć.

Brian Campbell
źródło
Dzięki za to - nie sądzę, że jestem w tej chwili wystarczająco oddany, aby przesłać łatkę. Jest to coś, czego prawdopodobnie i tak nie chciałbyś, aby się stało bez Twojej wiedzy. To trochę psuje piaskownicę przeglądarki ...
Damovisa,
4
Nie przerywa to piaskownicy przeglądarki, ponieważ celowo zdecydowałeś się przesłać ten plik; jeśli może dostać się do serwera, może wrócić do przeglądarki, po prostu z dodatkową podróżą w obie strony. Biorąc pod uwagę nakład pracy związany z pracą w trybie offline dla aplikacji internetowych, byłaby to rozsądna funkcja.
Brian Campbell
Mm, właściwie to słuszna uwaga. Wybranie tego pliku wymagało interakcji użytkownika. Dzięki.
Damovisa
@Damovisa Nie wiem, czy nadal Cię to obchodzi, ale pomyślałem, że zaktualizuję swoją odpowiedź, aby wspomnieć o nowym API plików, które robi to, czego szukasz, i jest zaimplementowane w Firefoksie, Chrome i nocnych kompilacjach Safari.
Brian Campbell
Świetnie, dzięki za to. Przeszedłem do innej pracy, ale dobrze jest wiedzieć, że odpowiedź jest tam :)
Damovisa
25

Aby odczytać plik wybrany przez użytkownika, korzystając z okna dialogowego otwierania pliku, możesz użyć <input type="file">tagu. Informacje na ten temat można znaleźć w witrynie MSDN . Po wybraniu pliku możesz użyć FileReader API do odczytania zawartości.

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
źródło
Nie działa w przeglądarce Internet Explorer.
Merwais Muafaq
4

Miłego kodowania!
Jeśli pojawi się błąd w przeglądarce Internet Explorer, zmień ustawienia zabezpieczeń, aby zezwolić na obsługę formantów 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;
  }
 }
Mnyikka
źródło