Lecture du contenu des fichiers côté client en javascript dans divers navigateurs

113

J'essaie de fournir une solution de script uniquement pour lire le contenu d'un fichier sur une machine cliente via un navigateur.

J'ai une solution qui fonctionne avec Firefox et Internet Explorer. Ce n'est pas joli, mais j'essaye seulement des choses pour le moment:

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

Je peux appeler getFileContents()et il écrira le contenu dans la fileContentszone de texte.

Existe-t-il un moyen de faire cela dans d'autres navigateurs?

Je suis plus préoccupé par Safari et Chrome pour le moment, mais je suis ouvert aux suggestions pour tout autre navigateur.

Edit: En réponse à la question "Pourquoi voulez-vous faire cela?":

Fondamentalement, je souhaite hacher le contenu du fichier avec un mot de passe à usage unique côté client afin de pouvoir renvoyer ces informations à titre de vérification.

Damovisa
la source
non pas que j'ai une réponse mais juste pour plus de clarté, avez-vous besoin de connaître l'emplacement du fichier? Sinon, est-ce que l'emplacement du fichier doit être lu à partir d'une entrée de fichier ou peut-il s'agir d'une zone de texte / zone de texte / quoi que ce soit?
Darko Z
Bonne question. Non, je ne me soucie pas vraiment de l'origine du fichier, seulement de son contenu. L'utilisation d'une entrée de fichier me semble cependant judicieuse car c'est du html natif - il y a une chose de moins à faire.
Damovisa
pourquoi voulez-vous faire cela? le serveur est destiné à le faire.
geowa4
Ok, en bref: un utilisateur entre un mot de passe et sélectionne un fichier. Le mot de passe est haché avec le contenu du fichier et celui-ci est envoyé au serveur avec le fichier. Quand il y arrive, je peux vérifier que le mot de passe client correct a été utilisé.
Damovisa

Réponses:

159

Modifié pour ajouter des informations sur l'API File

Depuis que j'ai initialement écrit cette réponse, l' API de fichier a été proposée comme standard et implémentée dans la plupart des navigateurs (à partir d'IE 10, qui a ajouté la prise en charge de l' FileReaderAPI décrite ici, mais pas encore l' FileAPI). L'API est un peu plus compliquée que l'ancienne API Mozilla, car elle est conçue pour prendre en charge la lecture asynchrone des fichiers, une meilleure prise en charge des fichiers binaires et le décodage de différents encodages de texte. Il existe une documentation disponible sur le Mozilla Developer Network ainsi que divers exemples en ligne. Vous l'utiliseriez comme suit:

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

Réponse originale

Il ne semble pas y avoir de moyen de le faire dans WebKit (donc Safari et Chrome). Les seules clés d'un objet File sont fileNameet fileSize. Selon le message de validation pour le support File et FileList, ceux-ci sont inspirés de l'objet File de Mozilla , mais ils semblent ne prendre en charge qu'un sous-ensemble des fonctionnalités.

Si vous souhaitez changer cela, vous pouvez toujours envoyer un correctif au projet WebKit. Une autre possibilité serait de proposer l'API Mozilla à inclure dans HTML 5 ; la liste de diffusion WHATWG est probablement le meilleur endroit pour le faire. Si vous faites cela, il est beaucoup plus probable qu'il y ait un moyen multi-navigateurs de le faire, au moins dans quelques années. Bien sûr, soumettre un correctif ou une proposition d'inclusion à HTML 5 signifie un travail de défense de l'idée, mais le fait que Firefox l'implémente déjà vous donne quelque chose pour commencer.

Brian Campbell
la source
Merci pour cela - je ne pense pas que je suis assez dédié à ce stade pour soumettre un correctif. C'est quelque chose que vous ne voudriez probablement pas de toute façon se produire à votre insu. Ça casse un peu le bac à sable du navigateur ...
Damovisa
4
Cela ne brise pas le bac à sable du navigateur, puisque vous avez délibérément choisi de télécharger ce fichier; s'il peut accéder au serveur, il peut revenir au navigateur, juste avec un aller-retour supplémentaire. Compte tenu du travail qui consiste à faire fonctionner le mode hors ligne pour les applications Web, ce serait une fonctionnalité raisonnable.
Brian Campbell
Mm, en fait c'est un bon point. Il y a eu une interaction de l'utilisateur pour choisir ce fichier. Merci.
Damovisa
@Damovisa Je ne sais pas si cela vous tient toujours à cœur, mais j'ai pensé que je mettrais à jour ma réponse pour mentionner la nouvelle API de fichier qui fait ce que vous recherchez et qui est implémentée dans Firefox, Chrome et les versions nocturnes de Safari.
Brian Campbell
Génial, merci pour ça. Je suis passé à un autre travail, mais il est bon de savoir que la réponse est là :)
Damovisa
25

Pour lire un fichier choisi par l'utilisateur, à l'aide d'une boîte de dialogue d'ouverture de fichier, vous pouvez utiliser la <input type="file">balise. Vous pouvez trouver des informations à ce sujet sur MSDN . Lorsque le fichier est choisi, vous pouvez utiliser l' API FileReader pour lire le contenu.

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
la source
Ne fonctionne pas dans Internet Explorer.
Merwais Muafaq le
4

Bon codage!
Si vous obtenez une erreur sur Internet Explorer, modifiez les paramètres de sécurité pour autoriser 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
la source