Ler o conteúdo do arquivo no lado do cliente em javascript em vários navegadores

113

Estou tentando fornecer uma solução somente de script para ler o conteúdo de um arquivo em uma máquina cliente por meio de um navegador.

Tenho uma solução que funciona com Firefox e Internet Explorer. Não é bonito, mas estou apenas tentando coisas no 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 :(";
    }
}

Posso ligar getFileContents()e ele escreverá o conteúdo na fileContentsárea de texto.

Existe uma maneira de fazer isso em outros navegadores?

Estou mais preocupado com o Safari e o Chrome no momento, mas estou aberto a sugestões para qualquer outro navegador.

Edit: Em resposta à pergunta "Por que você deseja fazer isso?":

Basicamente, quero fazer o hash do conteúdo do arquivo junto com uma senha de uso único no lado do cliente para que possa enviar essas informações de volta como uma verificação.

Damovisa
fonte
não que eu tenha uma resposta, mas apenas por uma questão de clareza, você precisa saber a localização do arquivo? Se não, a localização do arquivo deve ser lida a partir de uma entrada de arquivo ou pode ser uma caixa de texto / área de texto / qualquer coisa?
Darko Z de
Boa pergunta. Não, eu realmente não me importo com a origem do arquivo, apenas seu conteúdo. Usar uma entrada de arquivo parece sensato para mim, pois é html nativo - há uma coisa a menos que eu tenho que fazer.
Damovisa,
por que você quer fazer isso? o servidor foi feito para fazer isso.
geowa4 de
Ok, resumindo: um usuário insere uma senha e seleciona um arquivo. A senha é misturada com o conteúdo do arquivo e enviada para o servidor junto com o arquivo. Quando chegar lá, posso verificar se a senha correta do cliente foi usada.
Damovisa,

Respostas:

159

Editado para adicionar informações sobre a API File

Desde que escrevi esta resposta originalmente, a API de arquivo foi proposta como padrão e implementada na maioria dos navegadores (a partir do IE 10, que adicionou suporte para a FileReaderAPI descrita aqui, embora ainda não seja a FileAPI). A API é um pouco mais complicada do que a API Mozilla mais antiga, pois foi projetada para suportar a leitura assíncrona de arquivos, melhor suporte para arquivos binários e decodificação de diferentes codificações de texto. Há alguma documentação disponível na Mozilla Developer Network , bem como vários exemplos online. Você o usaria da seguinte maneira:

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

Resposta original

Não parece haver uma maneira de fazer isso no WebKit (portanto, Safari e Chrome). As únicas chaves que um objeto File possui são fileNamee fileSize. De acordo com a mensagem de confirmação para o suporte File e FileList, eles são inspirados no objeto File do Mozilla , mas parecem oferecer suporte a apenas um subconjunto dos recursos.

Se você quiser mudar isso, pode sempre enviar um patch para o projeto WebKit. Outra possibilidade seria propor a API Mozilla para inclusão no HTML 5 ; a lista de discussão WHATWG é provavelmente o melhor lugar para fazer isso. Se você fizer isso, é muito mais provável que exista uma maneira cross-browser de fazer isso, pelo menos em alguns anos. Claro, enviar um patch ou uma proposta para inclusão no HTML 5 significa algum trabalho defendendo a ideia, mas o fato de o Firefox já implementá-lo dá a você algo para começar.

Brian Campbell
fonte
Obrigado por isso - não acho que estou dedicado o suficiente neste momento para enviar um patch. É algo que você provavelmente não gostaria que acontecesse sem o seu conhecimento de qualquer maneira. Isso meio que quebra a sandbox do navegador ...
Damovisa,
4
Isso não quebra a sandbox do navegador, já que você escolheu deliberadamente fazer o upload desse arquivo; se pode chegar ao servidor, pode voltar ao navegador, apenas com uma viagem de ida e volta extra. Dado o trabalho que está sendo feito para fazer o modo offline funcionar para aplicativos da web, este seria um recurso razoável.
Brian Campbell,
Mm, na verdade esse é um ponto justo. Houve interação do usuário para escolher esse arquivo. Obrigado.
Damovisa
@Damovisa Não sei se você ainda se preocupa com isso, mas achei que deveria atualizar minha resposta para mencionar a nova API de arquivo que faz o que você está procurando e é implementada no Firefox, Chrome e compilações noturnas de Safári.
Brian Campbell
Incrível, obrigado por isso. Mudei para outro trabalho, mas é bom saber que a resposta está lá :)
Damovisa
25

Para ler um arquivo escolhido pelo usuário, usando uma caixa de diálogo de abertura de arquivo, você pode usar a <input type="file">tag. Você pode encontrar informações sobre ele no MSDN . Quando o arquivo é escolhido, você pode usar a API FileReader para ler o conteúdo.

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
fonte
Não funciona no Internet Explorer.
Merwais Muafaq
4

Boa codificação!
Se você receber um erro no Internet Explorer, altere as configurações de segurança 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
fonte