Question

J'ai récemment contribué un code à Moodle qui utilise certaines des fonctionnalités de HTML5 pour permettre aux fichiers d'être téléchargés sous forme par glisser-déposer depuis le bureau (la partie centrale du code est ici: https://github.com/moodle/moodle/blob/master/lib/form/dndupload js pour référence).

Cela fonctionne bien, sauf lorsqu'un utilisateur drags un répertoire dossier / au lieu d'un fichier réel. Garbage est ensuite téléchargé sur le serveur, mais avec le nom du fichier correspondant au dossier.

Ce que je cherche est un moyen facile et fiable à détecter la présence d'un dossier FileList objet, donc je ne peux sauter (et probablement revenir un message d'erreur convivial ainsi).

Je l'ai regardé à travers la documentation sur MDN, ainsi qu'une recherche sur le Web plus général, mais ne se détourne pas quoi que ce soit. Je l'ai aussi regardé les données dans les outils de développement Chrome et il semble que le « type » de l'objet fichier est toujours réglé sur « » pour les dossiers. Cependant, je ne suis pas tout à fait convaincu que c'est la plus fiable, la méthode de détection multi-navigateur.

Quelqu'un at-il de meilleures suggestions?

Était-ce utile?

La solution

Vous ne pouvez pas compter sur file.type. Un fichier sans extension aura un type de "". Enregistrer un fichier texte avec une extension .jpg et le charger dans un contrôle de fichiers et son type affiche comme image/jpeg. Et, un dossier nommé « someFolder.jpg » aura aussi son type que image/jpeg.

Essayez de lire le fichier avec un FileReader. Si un répertoire est traîné dans la FileReader soulèvera l'événement error:

var reader = new FileReader();
reader.onload = function (e) {
    // it's a file
};
reader.onerror = function (e) {
    // it's a directory
};
reader.readAsText(file);

Heureusement, dans IE11, quand un répertoire est tombé, la collection e.dataTransfer.files est vide.

Chrome expose une propriété supplémentaire dans e.dataTransfer appelé items contenant une collection d'objets DataTransferItem. Sur chacun de ces objets, vous pouvez appeler item.webkitGetAsEntry(), qui retourne un objet Entry. L'objet Entry a des propriétés isDirectory et isFile:

// Chrome only
if (e.dataTransfer.items && e.dataTransfer.items.length) {
   [].forEach.call(e.dataTransfer.items, function(item) {
      var entry = item.webkitGetAsEntry();
      if (entry && entry.isFile) {
         var file = item.getAsFile(); // same as object in e.dataTransfer.files[]
         // do something with the file
      }
   }
}

Il est intéressant, dans mon expérimentation, chaque dossier que je l'ai regardé a eu son File.size % 4096 zéro. Cependant, bien sûr, certains fichiers auront aussi. File.size est pas un indicateur fiable de savoir si un fichier est en fait un dossier.

Autres conseils

J'ai aussi rencontré ce problème et ci-dessous est ma solution. Au fond, je pris une approche à deux volets:

(1) vérifier si la taille de l'objet fichier est grande, et le considèrent comme un fichier authentique si elle est au-dessus de 1 Mo (je suppose que les dossiers eux-mêmes ne sont jamais aussi grand). (2) Si l'objet de fichier est plus petit que 1 Mo, puis je l'ai lu en utilisant la méthode de « readAsArrayBuffer » FileReader. Le succès lit appel « onload » et je crois que cela indique l'objet de fichier est un fichier authentique. Failed lit appel 'onerror et je considère comme un répertoire. Voici le code:

var isLikelyFile = null;
if (f.size > 1048576){ isLikelyFile = false; }
else{
    var reader = new FileReader();
    reader.onload = function (result) { isLikelyFile = true; };
    reader.onerror = function(){ isLikelyFile = false; };
    reader.readAsArrayBuffer(f);
}
//wait for reader to finish : should be quick as file size is < 1MB ;-)
var interval = setInterval(function() {
    if (isLikelyFile != null){
        clearInterval(interval);
        console.log('finished checking File object. isLikelyFile = ' + isLikelyFile);
    }
}, 100);

Je l'ai testé cela dans FF 26, 31 Chrome et Safari 6 et trois navigateurs appelle « onerror » lorsque vous tentez de lire des répertoires. Faites-moi savoir si quelqu'un peut penser à un cas d'utilisation où cela ne fonctionne pas.

Je propose d'appeler FileReader.readAsBinaryString sur l'objet File. Dans Firefox, cela déclenche une exception lorsque la File est un Directory. Je ne fais que cela si l'File satisfait aux conditions proposées par gilly3.

S'il vous plaît voir mon blog http :. //hs2n.wordpress.com/2012/08/13/detecting-folders-in-html-drop-area/ pour plus de détails

En outre, la version 21 de Google Chrome prend désormais en charge les dossiers tomber. Vous pouvez facilement vérifier si les éléments sont des dossiers a chuté, et aussi lire leur contenu.

Malheureusement, je ne disposons pas de solution (côté client) pour les versions Chrome plus.

Une autre note est que le type est « » pour tout fichier qui a une extension inconnue. Essayez de télécharger un fichier nommé test.blah et le type sera vide. ET ... essayez de glisser-déposer un dossier nommé test.jpg - type sera réglé sur « image / jpeg ». Pour être 100% correct, vous ne pouvez pas dépendre uniquement du type (ou le cas échéant, vraiment).

Dans mes tests, les dossiers ont toujours été de taille 0 (sur FF et Chrome 64 bits Windows 7 et sous Linux Mint (Ubuntu essentiellement). Donc, mon chèque de dossier est en train de vérifier si la taille est 0 et il semble . le travail pour moi dans notre environnement Nous ne voulons pas les fichiers de 0 octet téléchargés soit s'il est 0 octet le message revient comme « Ignoré - 0 octets (ou dossier) »

Pour votre information, ce poste vous dira comment utiliser l'API dataTransfer dans Chrome pour détecter le type de fichier: http://updates.html5rocks.com/2012/07/Drag-and-drop-a-folder-onto-Chrome-now-available

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top