Detecting folders / directories in javascript FileList objects

I recently contributed some code to Moodle, which uses some HTML5 features to allow the loading of files in forms using drag and drop from the desktop (the main part of the code is here: https://github.com/moodle/moodle/blob/master/lib/ form / dndupload.js for reference).

This works well unless the user drags the folder instead of a real file. Then the garbage is downloaded to the server, but with the file name corresponding to the folder.

I am looking for a simple and reliable way to detect the presence of a folder in a FileList object, so I can skip it (and probably return a friendly error message).

I looked at the MDN documentation as well as the more general web search, but didn't understand anything. I also looked at the data in the Chrome developer tools, and it seems that the 'type of the File object is set to "" . However, I'm not quite sure if this is the most reliable cross browser detection method.

Does anyone have any better suggestions?

+8
html5 file-upload drag-and-drop filelist moodle
source share
5 answers

You cannot rely on file.type . A file without an extension will be of type "" . Save the text file with the extension .jpg and load it into the control file, and its type will be displayed as image/jpeg . And a folder named "someFolder.jpg" will also be of type image/jpeg .

Try to read the file using FileReader . If the directory is dragged, FileReader raises the error event:

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

Fortunately, in IE11, when the directory is dropped, the e.dataTransfer.files collection e.dataTransfer.files empty.

Chrome provides an additional property in e.dataTransfer called items that contains a collection of DataTransferItem objects. On each of these objects, you can call item.webkitGetAsEntry() , which returns an Entry object. The Entry object has the properties isDirectory and 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 } } } 

Interestingly, in my experiments, every folder I looked at had File.size % 4096 to zero. However, of course, some files will also have this. File.size not a reliable indicator of whether a file is really a folder.

+17
source share

I also ran into this problem, and below is my solution. Basically, I had a two-way approach:

(1) check if the File object is large and consider it a genuine file if it exceeds 1 MB (I assume that the folders themselves are never so large). (2) If the File object is less than 1 MB, I read it using the ReadAsArrayBuffer FileReader method. A successful read causes "onload", and I believe that this means that the file object is a genuine file. A read failure causes "onerror", and I consider it a directory. Here is the 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); 

I tested this on FF 26, Chrome 31, and Safari 6, and three browsers raise "onerror" when trying to read directories. Let me know if anyone can think of a use case when this fails.

+6
source share

I suggest calling FileReader.readAsBinaryString a File object. In Firefox, this will throw an exception if File is a Directory . I only do this if File meets the conditions suggested by gilly3.

See my blog at http://hs2n.wordpress.com/2012/08/13/detecting-folders-in-html-drop-area/ for more details.

In addition, version 21 of Google Chrome now supports deleting folders. You can easily check if the fallen items are folders, and also read their contents.

Unfortunately, I donโ€™t have a (client) solution for earlier versions of Chrome.

+2
source share

One more note: type "for any file with an unknown extension. Try downloading a file called test.blah and the type will be empty. And ... try dragging a folder called test.jpg - the type will be set to" image / jpeg ". To be 100% correct, you cannot depend only on type (or, if at all, really).

In my testing, the folders were always 0 in size (in FF and Chrome on 64-bit Windows 7 and under Linux Mint (essentially Ubuntu). Thus, checking my folder checks if the size is 0, and it seems that we are working for me in our environment, we also donโ€™t want 0-byte files to be loaded, so if it is 0 bytes, the message is returned as โ€œSkipped - 0 bytes (or folder)โ€

0
source share

FYI, this post will tell you how to use the DataTransfer API in Chrome to determine the file type: http://updates.html5rocks.com/2012/07/Drag-and-drop-a-folder-onto-Chrome-now-available

0
source share

All Articles