Leer el contenido del archivo en el lado del cliente en javascript en varios navegadores

113

Estoy intentando proporcionar una solución de solo script para leer el contenido de un archivo en una máquina cliente a través de un navegador.

Tengo una solución que funciona con Firefox e Internet Explorer. No es bonito, pero solo estoy probando cosas en este momento:

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

Puedo llamar getFileContents()y escribirá el contenido en el fileContentsárea de texto.

¿Hay alguna forma de hacer esto en otros navegadores?

Estoy más preocupado por Safari y Chrome en este momento, pero estoy abierto a sugerencias para cualquier otro navegador.

Editar: En respuesta a la pregunta, "¿Por qué quieres hacer esto?":

Básicamente, quiero codificar el contenido del archivo junto con una contraseña de un solo uso en el lado del cliente para poder enviar esta información como verificación.

Damovisa
fuente
no es que tenga una respuesta, pero solo en aras de la claridad, ¿necesita saber la ubicación del archivo? Si no es así, ¿la ubicación del archivo debe leerse desde una entrada de archivo o puede ser un cuadro de texto / área de texto / lo que sea?
Darko Z
Buena pregunta. No, realmente no me importa de dónde viene el archivo, solo su contenido. Sin embargo, usar una entrada de archivo me parece sensato, ya que es html nativo; hay una cosa menos que tengo que hacer.
Damovisa
¿Por qué quieres hacer esto? el servidor está destinado a hacer eso.
geowa4
Ok, en resumen: un usuario ingresa una contraseña y selecciona un archivo. La contraseña se codifica con el contenido del archivo y se envía al servidor junto con el archivo. Cuando llegue allí, puedo verificar que se utilizó la contraseña de cliente correcta.
Damovisa

Respuestas:

159

Editado para agregar información sobre la API de archivos

Desde que escribí originalmente esta respuesta, la API de archivo se propuso como estándar y se implementó en la mayoría de los navegadores (a partir de IE 10, que agregó soporte para la FileReaderAPI descrita aquí, aunque aún no la FileAPI). La API es un poco más complicada que la API de Mozilla anterior, ya que está diseñada para admitir la lectura asincrónica de archivos, mejor soporte para archivos binarios y decodificación de diferentes codificaciones de texto. Existe cierta documentación disponible en Mozilla Developer Network , así como varios ejemplos en línea. Lo usaría de la siguiente manera:

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

Respuesta original

No parece haber una forma de hacer esto en WebKit (por lo tanto, Safari y Chrome). Las únicas claves que tiene un objeto File son fileNamey fileSize. Según el mensaje de confirmación para el soporte de File y FileList, estos están inspirados en el objeto File de Mozilla , pero parecen admitir solo un subconjunto de las características.

Si desea cambiar esto, siempre puede enviar un parche al proyecto WebKit. Otra posibilidad sería proponer la API de Mozilla para su inclusión en HTML 5 ; la lista de correo WHATWG es probablemente el mejor lugar para hacerlo. Si lo hace, es mucho más probable que haya una forma de hacerlo en varios navegadores, al menos en un par de años. Por supuesto, enviar un parche o una propuesta para su inclusión en HTML 5 significa algo de trabajo para defender la idea, pero el hecho de que Firefox ya lo implemente te da algo para empezar.

Brian Campbell
fuente
Gracias por eso, no creo que me dedique lo suficiente en este momento para enviar un parche. Es algo que probablemente no querrías que sucediera sin tu conocimiento de todos modos. Rompe un poco la caja de arena del navegador ...
Damovisa
4
No rompe la caja de arena del navegador, ya que ha elegido deliberadamente cargar ese archivo; si puede llegar al servidor, puede volver al navegador, solo con un viaje de ida y vuelta adicional. Dado el trabajo que se está realizando para hacer que el modo fuera de línea funcione para aplicaciones web, esta sería una característica razonable.
Brian Campbell
Mm, en realidad ese es un buen punto. Hubo interacción del usuario para elegir ese archivo. Gracias.
Damovisa
@Damovisa No sé si todavía te importa esto, pero pensé que actualizaría mi respuesta para mencionar la nueva API de archivos que hace lo que estás buscando y está implementada en Firefox, Chrome y compilaciones nocturnas de Safari.
Brian Campbell
Impresionante, gracias por eso. He pasado a otro trabajo, pero es bueno saber que la respuesta está ahí :)
Damovisa
25

Para poder leer un archivo seleccionado por el usuario, utilizando un cuadro de diálogo de apertura de archivo, puede utilizar la <input type="file">etiqueta. Puede encontrar información al respecto en MSDN . Cuando se elige el archivo, puede usar la API FileReader para leer el contenido.

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
fuente
No funciona en Internet Explorer.
Merwais Muafaq
4

¡Feliz codificación!
Si obtiene un error en Internet Explorer, cambie la configuración de seguridad para permitir 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
fuente