26

How do I upload the content of a folder using JavaScript (client side)? The FileSystem API has not been adopted by browsers other than Chrome; I only get a File item with the name of the folder.

It should be possible, because Google Drive allows to drop a folder and all the content (folders and files) will be uploaded automatically.

7 Answers 7

14

You can actually upload directories in all latest versions of Chrome, Firefox and Microsoft Edge. There are numerous working examples available to look at.

Here is a good, working example that I've previously used in a project

Quarklemotion Html5FileSelector

In addition, Dropzone JS also supports directory uploads as well and it works in Chrome, FF and Edge. I've just transitioned to using this in my own project.

Dropzone JS

These solutions recursively read the directory entries and list all of the files including their relative paths. If you want to rebuild the folder structure when uploading you will have to implement that using the relative paths and the appropriate algorithm.

Sign up to request clarification or add additional context in comments.

4 Comments

I wouldn't recommend Dropzone today. It seems to have fallen into abandonware, and will likely just get in your way more than help. There's nothing particularly challenging about uploading files.
@JoshNoe I'm curious why you assume that Dropzone is "abandonware" and why you wouldn't recommend it? It's under active development and the last release was in September 2021, a few months ago. There may not be anything crazy challenging about uploading files this question is about more than uploading files. It's about recursively reading directories and uploading all of the files from a directory and any nested dirs. In 2017 this wasn't as trivial. I've provided a roll-your-own solution and then a lib (Dropzone) that does it for you out of the box. Did you have anything constructive to add?
I wouldn't recommend dropzone in 2022 for recursively reading directories because it's going to take one much longer to integrate dropzone than simply using webkitdirectory or one of the other answers here. Fair enough that it's not literally abandonware, but its documentation is full of dead links and obsolete code, and very limited at that.
We use DropZone for a while, and original path is also retrieved when a folder is uploaded. Little adaptation on server side and it can also support folder tree.
14

It seems that Chrome and Firefox supports part of the filesystem API, but are not oficially supported.

This allows you to drop a folder and read all the content, here's the code i use on my app.

    function addFiles(e){
        e.stopPropagation();
        e.preventDefault();

        // if directory support is available
        if(e.dataTransfer && e.dataTransfer.items)
        {
            var items = e.dataTransfer.items;
            for (var i=0; i<items.length; i++) {
                var item = items[i].webkitGetAsEntry();

                if (item) {
                  addDirectory(item);
                }
            }
            return;
        }

        // Fallback
        var files = e.target.files || e.dataTransfer.files;
        if (!files.length)
        {
            alert('File type not accepted');
            return;
        }

        processFile(files);
    }

    function addDirectory(item) {
        var _this = this;
        if (item.isDirectory) {
            var directoryReader = item.createReader();
            directoryReader.readEntries(function(entries) {
            entries.forEach(function(entry) {
                    _this.addDirectory(entry);
                });
            });
        } else {
            item.file(function(file){
                processFile([file],0);
            });
        }
    },

2 Comments

if I want path of the each file(Beginning path from the uploaded folder) , what changes I have to do?. Because in my project I am sending each file to backend ,there I am creating same structure of the uploaded folder.
@Avinash here is a script you can look at where I rebuilt the folder structure when uploading directories. This is open source github.com/caseychoiniere/duke-data-service-portal/blob/…
8

You can use the webkitdirectory property:

let picker = document.getElementById('picker');
let listing = document.getElementById('listing');

picker.addEventListener('change', e => {
  for (let file of Array.from(e.target.files)) {
    let item = document.createElement('li');
    item.textContent = file.webkitRelativePath;
    listing.appendChild(item);
  };
});
(Forked from <a href='https://codepen.io/simevidas'>Šime Vidas' Pen</a> for posting on Stack Overflow)<br><br>

<div class="picker"><input type="file" id="picker" name="fileList" webkitdirectory multiple></div>

<ul id="listing"></ul>

Comments

2
  • For implement the folder upload, you need apply both of JS side and server side:
  • At JS side I use these methods (from a teacher that posted at StackoverFlow - https://stackoverflow.com/a/47935286/11544097) to loop and file all file, folder content and subfolders:

    function makedir(entries) {
      const systems = entries.map(entry => traverse(entry, {}));
      return Promise.all(systems);
    
      async function traverse(entry, fs) {
        if (entry.isDirectory) {
          fs[entry.name] = {};
          let dirReader = entry.createReader();
          await new Promise((res, rej) => {
        dirReader.readEntries(async entries => {
          for(let e of entries) {
            await traverse(e, fs[entry.name]);
          }
          res();
        }, rej);
          });
        } else if (entry.isFile) {
          await new Promise((res, rej) => {
        entry.file(file => {
          fs[entry.name] = file;
          res();
        }, rej);
          });
        }
      return fs;
      }
    };
    
    function checkFile(obj){
        return obj instanceof File;
    };
    
    function exactFile(system_trees, relativePath, files){
        for (var i = 0; i < system_trees.length; i++){
            for (var property in system_trees[i]) {
                if (system_trees[i].hasOwnProperty(property)) {
                    if (checkFile(system_trees[i][property])){
                        system_trees[i][property]["relativePath"] = relativePath;
                        files.push(system_trees[i][property]);
                    } else {
                        files.concat(exactFile([system_trees[i][property]], (typeof relativePath !== 'undefined' && relativePath !== '' ? (relativePath + '/') : '') + property, files));
                    }
                }
            }
        }
        return files;
    };
    
    function readDropped(dT,_data) {
      const entries = [...dT.items].map(item => {
          return item.webkitGetAsEntry ? item.webkitGetAsEntry() : null;
        })
        .filter(entry => entry);
      if (entries.length) {
        makedir(entries).then(function(system_trees){
            var files = exactFile(system_trees, "", []);
            c(_data, files);
        }).catch(function(){
            var files = dT.files;
            c(_data, files);
        });
      } else {
            var files = dT.files;
            c(_data, files);
      }
    };
    
  • The 'dT' is drop event (e.originalEvent.dataTransfer) and '_data' that is Ajax upload submit form.
  • You also need a upload library or write it by yourself to send to file into server by ajax upload. In the code example above, I use formstone upload library (https://formstone.it/components/upload/)

  • At server side: You need to process the form data that was sent from JS side, al most case you need to process file by file with relative path info enclosed from the File object.

  • One more note, just set 'multiple' attribute at file upload input, NO need a 'webkitdirectory' or 'directory'. They caused the user can not choose the file (only folder allowed)

  • The result you will have the uploading system support all folder and files will keeping their structure like Google Drive :).

  • There is the tool (https://freetoolonline.com/zip-file.html) that I have wrote that supports folder upload based on the ideal I have explained above.

Comments

0

We succesd to send a full tree of folder with DropZone. Folder as such are not uploaded, but each file will also send original path/local file system path. After is on server side where some work have to be done to properly handle it.

var dropzone = new Dropzone('my-div-class', {
    ...
    sending : function(file, xhr, formData) {
        // Add custom data to send with each file
        // file.fullPath contain relative path to filename from uploaded folder
        formData.append("originalFullPath", file.fullPath);
    }
})

Comments

0

In 2025, the webkitdirectory attribute of input element is not standard yet, but widely accepted.

With this attribute,

<input type="file" name="file" webkitdirectory />

you can select only directories, not files. Once selected, the browser collects all the files in the directory and subdirectories recursively and change the name of the files automatically to reflect the directory structure.

For example, if you chose the rootdir

rootdir/
  - file1.ext
  - subdir1/
    - file2.ext
  - subdir2/

you will get two file objects with

- "rootdir/file1.ext"
- "rootdir/subdir1/file2.ext"

as their names respectively, so that you can easily reconstruct the directory structure from the formData at the server side. Note that empty directories are not selected though.

Comments

-2

Unfortunately, only webkit-based browsers support the filesystem API at this point.

If you try to drop a folder in Google Drive using firefox or internet explorer, you will get an error message saying it's not supported.

1 Comment

Google Drive under Firefox supports dropping a folder to upload all its contents & subfolders

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.