क्या HTML5 फ़ोल्डर्स या फ़ोल्डर ट्री के ड्रैग-ड्रॉप अपलोड की अनुमति देता है?


82

मैंने ऐसा कोई उदाहरण नहीं देखा है जो ऐसा करता हो। क्या एपीआई युक्ति में इसकी अनुमति नहीं है?

मैं फ़ोटो के संपूर्ण फ़ोल्डर ट्री को अपलोड करने के लिए एक आसान ड्रैग-ड्रॉप समाधान खोज रहा हूं।



जवाबों:


81

यह अब संभव है, Chrome> = 21 के लिए धन्यवाद।

function traverseFileTree(item, path) {
  path = path || "";
  if (item.isFile) {
    // Get file
    item.file(function(file) {
      console.log("File:", path + file.name);
    });
  } else if (item.isDirectory) {
    // Get folder contents
    var dirReader = item.createReader();
    dirReader.readEntries(function(entries) {
      for (var i=0; i<entries.length; i++) {
        traverseFileTree(entries[i], path + item.name + "/");
      }
    });
  }
}

dropArea.addEventListener("drop", function(event) {
  event.preventDefault();

  var items = event.dataTransfer.items;
  for (var i=0; i<items.length; i++) {
    // webkitGetAsEntry is where the magic happens
    var item = items[i].webkitGetAsEntry();
    if (item) {
      traverseFileTree(item);
    }
  }
}, false);

अधिक जानकारी: https://protonet.info/blog/html5-experiment-drag-drop-of-folders/


9
2 साल बाद भी, IE और फ़ायरफ़ॉक्स इसे लागू करने के लिए तैयार नहीं दिख रहे हैं।
निकोलस राउल

8
अब, फ़ायरफ़ॉक्स के लिए भी: stackoverflow.com/a/33431704/195216 यह ड्रैगनेन के माध्यम से अपलोड करने और क्रोम और फ़ायरफ़ॉक्स में संवाद के माध्यम से फ़ोल्डर को दिखाता है!
dforce

2
एज भी इस बात का समर्थन करता है।
ZachB

7
महत्वपूर्ण चेतावनी: इस उत्तर में कोड दिए गए डायरेक्टरी में 100 फाइलों तक सीमित है। यहाँ देखें: bugs.chromium.org/p/chromium/issues/detail?id=514087
johnozbay

4
@johnozbay यह दुर्भाग्यपूर्ण है कि अधिक लोगों ने आपकी महत्वपूर्ण चेतावनी को उठाया, और यह जरूरी नहीं है कि क्रोमियम मुद्दा है क्योंकि यह कहता है कि readEntriesनिर्देशिका में सभी एंटायर वापस नहीं आएंगे। आपके द्वारा दिए गए बग लिंक के आधार पर, मैंने एक पूर्ण उत्तर लिखा है: stackoverflow.com/a/53058574/885922
xlm

49

दुर्भाग्यवश मौजूदा उत्तरों में से कोई भी पूरी तरह से सही readEntriesनहीं है क्योंकि किसी दिए गए निर्देशिका के लिए सभी (फ़ाइल या निर्देशिका) प्रविष्टियों को जरूरी नहीं लौटाया जाएगा । यह एपीआई विनिर्देश का हिस्सा है (नीचे प्रलेखन अनुभाग देखें)।

वास्तव में सभी फाइलें प्राप्त करने के लिए, हमें readEntriesएक खाली सरणी वापस आने तक बार-बार कॉल करने की आवश्यकता होगी (प्रत्येक निर्देशिका जो हम मुठभेड़ करते हैं)। यदि हम नहीं करते हैं, तो हम एक निर्देशिका में कुछ फ़ाइलों / उप-निर्देशिकाओं को याद करेंगे जैसे कि क्रोम में, readEntriesकेवल एक समय में अधिकतम 100 प्रविष्टियों में वापस आ जाएगी।

का उपयोग करते हुए वादे ( await/ async) और अधिक स्पष्ट रूप से सही उपयोग प्रदर्शित करने के लिए readEntries(क्योंकि यह अतुल्यकालिक है), और चौड़ाई-पहले खोज (BFS) निर्देशिका संरचना पार करने के लिए:

// Drop handler function to get all files
async function getAllFileEntries(dataTransferItemList) {
  let fileEntries = [];
  // Use BFS to traverse entire directory/file structure
  let queue = [];
  // Unfortunately dataTransferItemList is not iterable i.e. no forEach
  for (let i = 0; i < dataTransferItemList.length; i++) {
    queue.push(dataTransferItemList[i].webkitGetAsEntry());
  }
  while (queue.length > 0) {
    let entry = queue.shift();
    if (entry.isFile) {
      fileEntries.push(entry);
    } else if (entry.isDirectory) {
      queue.push(...await readAllDirectoryEntries(entry.createReader()));
    }
  }
  return fileEntries;
}

// Get all the entries (files or sub-directories) in a directory 
// by calling readEntries until it returns empty array
async function readAllDirectoryEntries(directoryReader) {
  let entries = [];
  let readEntries = await readEntriesPromise(directoryReader);
  while (readEntries.length > 0) {
    entries.push(...readEntries);
    readEntries = await readEntriesPromise(directoryReader);
  }
  return entries;
}

// Wrap readEntries in a promise to make working with readEntries easier
// readEntries will return only some of the entries in a directory
// e.g. Chrome returns at most 100 entries at a time
async function readEntriesPromise(directoryReader) {
  try {
    return await new Promise((resolve, reject) => {
      directoryReader.readEntries(resolve, reject);
    });
  } catch (err) {
    console.log(err);
  }
}

कोडपेन पर पूरा कार्य करने वाला उदाहरण: https://codepen.io/anon/pen/gBJrOP

एफडब्ल्यूआईडब्ल्यू मैंने केवल इसे उठाया क्योंकि मुझे स्वीकार किए गए उत्तर का उपयोग करते समय 40,000 फाइलों (कई निर्देशिकाओं में अच्छी तरह से 100 फाइलों / उप-निर्देशिकाओं से युक्त) में अपेक्षित सभी फाइलें वापस नहीं मिल रही थीं।

प्रलेखन:

इस व्यवहार में प्रलेखित है FileSystemDirectoryReader । जोर के साथ जोड़ा:

readEntries ()
एक सरणी देता है जिसमें कुछ संख्या होती है निर्देशिका की प्रविष्टियों। सरणी में प्रत्येक आइटम FileSystemEntry पर आधारित एक वस्तु है - आमतौर पर या तो FileSystemFileEntry या FileSystemDirectoryEntry।

लेकिन निष्पक्ष होने के लिए, एमडीएन प्रलेखन अन्य वर्गों में यह स्पष्ट कर सकता है। ReadEntries () प्रलेखन बस नोट:

readEntries () विधि निर्देशिका निर्देशिका को पढ़ा जा रहा है और उन्हें उपलब्ध कॉलबैक फ़ंक्शन में एक सरणी में वितरित करता है

और केवल उल्लेख / संकेत है कि कई कॉल की जरूरत है के विवरण में है सफल कॉलबैक पैरामीटर :

यदि कोई फ़ाइल नहीं बची है, या आपने पहले से ही इस FileSystemDirectoryReader पर readEntries () कहा है, तो सरणी खाली है।

यकीनन एपीआई अधिक सहज हो सकता है, लेकिन प्रलेखन नोटों के रूप में: यह एक गैर-मानक / प्रायोगिक विशेषता है, एक मानक ट्रैक पर नहीं, और सभी ब्राउज़रों के लिए काम करने की उम्मीद नहीं की जा सकती है।

सम्बंधित:

  • johnozbay टिप्पणी करता है कि Chrome पर, readEntriesएक निर्देशिका के लिए अधिकतम 100 प्रविष्टियों (Chrome 64 के रूप में सत्यापित) पर वापस आ जाएगा।
  • XanreadEntries इस उत्तर में काफी अच्छी तरह से सही उपयोग बताता है (यद्यपि कोड के बिना)।
  • पाब्लो बैरिया उरेंडा का जवाब सही ढंग से बीएफएस केreadEntries बिना एक अतुल्यकालिक तरीके से कहता है। वह यह भी नोट करता है कि फ़ायरफ़ॉक्स एक निर्देशिका में (क्रोम के विपरीत) सभी प्रविष्टियाँ लौटाता है लेकिन हम इस दिए गए विनिर्देश पर भरोसा नहीं कर सकते हैं।

4
शाउट-आउट के लिए बहुत बहुत धन्यवाद, और इस सामग्री को वहां से प्राप्त करना। SOF को अपने जैसे और शानदार सदस्यों की आवश्यकता है! ✌🏻
जॉन्जॉबाय

6
मैं सराहना करता हूं कि @johnozbay मैं बस चिंतित हूं कि ऐसा लगता है कि कई उपयोगकर्ता इस छोटे लेकिन महत्वपूर्ण तथ्य को फिर से देख रहे हैं: विनिर्देश / एपीआई और यह बढ़त मामला (एक निर्देशिका में 100 + फाइलें) ऐसा नहीं है। मुझे केवल इसका एहसास हुआ जब मुझे उन सभी फाइलों को वापस नहीं मिल रहा था जिनकी मुझे उम्मीद थी। आपकी टिप्पणी का जवाब होना चाहिए था।
xlm

फ़ाइल का आकार कैसे प्राप्त करें?
3

सभी प्रासंगिक मेटाडेटा (आकार, lastModified, माइम प्रकार) प्राप्त करने के लिए, आपको विधि के माध्यम से सभी FileSystemFileEntryको परिवर्तित करने की आवश्यकता है । यदि आपको भी पूर्ण मार्ग की आवश्यकता है, तो आपको इसे ( केवल नाम होगा) से लेना चाहिए । Filefile(successCb, failureCb)fileEntry.fullPathfile.webkitRelativePath
इस्क्राइन इवोव चेर्नेव

यह सबसे अच्छा उत्तर लगता है, लेकिन क्रोमियम 86 में मेरे लिए काम नहीं करता है। फ़ायरफ़ॉक्स में ठीक काम करता है। क्रोमियम में यह फाइलों से युक्त चयनों को अपलोड करेगा, लेकिन एक निर्देशिका के लिए कुछ भी अपलोड नहीं किया जाता है क्योंकि readEntriesPromise () एक खाली सरणी देता है।
खुश

15

यह फ़ंक्शन आपको सभी गिराई गई फ़ाइलों की सरणी के लिए एक वादा देगा, जैसे <input type="file"/>.files:

function getFilesWebkitDataTransferItems(dataTransferItems) {
  function traverseFileTreePromise(item, path='') {
    return new Promise( resolve => {
      if (item.isFile) {
        item.file(file => {
          file.filepath = path + file.name //save full path
          files.push(file)
          resolve(file)
        })
      } else if (item.isDirectory) {
        let dirReader = item.createReader()
        dirReader.readEntries(entries => {
          let entriesPromises = []
          for (let entr of entries)
            entriesPromises.push(traverseFileTreePromise(entr, path + item.name + "/"))
          resolve(Promise.all(entriesPromises))
        })
      }
    })
  }

  let files = []
  return new Promise((resolve, reject) => {
    let entriesPromises = []
    for (let it of dataTransferItems)
      entriesPromises.push(traverseFileTreePromise(it.webkitGetAsEntry()))
    Promise.all(entriesPromises)
      .then(entries => {
        //console.log(entries)
        resolve(files)
      })
  })
}

उपयोग:

dropArea.addEventListener("drop", function(event) {
  event.preventDefault();

  var items = event.dataTransfer.items;
  getFilesFromWebkitDataTransferItems(items)
    .then(files => {
      ...
    })
}, false);

npm पैकेज

https://www.npmjs.com/package/datatransfer-files-promise

उपयोग का उदाहरण: https://github.com/grabantot/datatransfer-files-promise/blob/master/index.html


4
यह नया स्वीकृत उत्तर होना चाहिए। यह अन्य उत्तरों से बेहतर है क्योंकि यह एक वादा पूरा होने पर देता है। लेकिन कुछ गलतियाँ थीं: function getFilesWebkitDataTransferItems(dataTransfer)होनी चाहिए function getFilesWebkitDataTransferItems(items), और for (entr of entries)होनी भी चाहिए for (let entr of entries)
रोक्को बीओपी

1
वास्तव में सभी फाइलों को एक निर्देशिका में नहीं मिलेगा (क्रोम के लिए यह केवल एक निर्देशिका में 100 प्रविष्टियाँ लौटाएगा)। विशिष्ट readEntriesबार-बार कॉल करने की आवश्यकता को तब तक निर्धारित करता है जब तक कि वह खाली सरणी नहीं देता।
xlm

@ xlm अपडेटेड npm पैकेज। अब यह 100 प्रविष्टियों को संभालता है।
१६

बहुत मददगार! समाधान के लिए धन्यवाद। अब तक यह सबसे सटीक और साफ है। यह नया स्वीकृत उत्तर होना चाहिए, मैं सहमत हूं।
सिद्धार्थ चौधरी

13

HTML 5 मेलिंग सूची में इस संदेश में इयान हिकसन कहते हैं:

HTML5 को अब एक साथ कई फाइलें अपलोड करनी हैं। ब्राउजर उपयोगकर्ताओं को एक साथ कई फाइलें लेने की अनुमति दे सकता है, जिसमें कई निर्देशिकाएं शामिल हैं; यह कल्पना के दायरे से बाहर है।

(मूल भी देखें फीचर प्रस्ताव ।) इसलिए यह मान लेना सुरक्षित है कि वह ड्रैग-एंड-ड्रॉप का उपयोग करके फ़ोल्डर्स अपलोड करने पर भी विचार करता है। जाहिर है यह व्यक्तिगत फ़ाइलों की सेवा करने के लिए ब्राउज़र पर निर्भर है।

फ़ोल्डर अपलोड करने में कुछ अन्य कठिनाइयाँ भी होंगी, जैसा कि लार्स गुनथर द्वारा वर्णित है :

इस […] प्रस्ताव में दो जाँचें होनी चाहिए (यदि यह सब करने योग्य है):

  1. अधिकतम आकार, किसी को कई सौ असम्पीडित कच्ची छवियों की पूर्ण निर्देशिका अपलोड करने से रोकने के लिए ...

  2. फ़िल्टरिंग भले ही स्वीकार विशेषता छोड़ दी गई हो। मैक ओएस मेटाडेटा और विंडोज थंबनेल आदि को छोड़ दिया जाना चाहिए। सभी छिपी हुई फ़ाइलों और निर्देशिकाओं को बाहर रखा जाना चाहिए।


हम्म, मैं बिंदु 2 पर सहमत हूं ... लेकिन जब तक कि वेब डेवलपर के पास यह निर्धारित करने के लिए कोई रास्ता नहीं है कि क्या वे छिपी हुई फ़ाइलों के अपलोड को सक्षम करना चाहते हैं - क्योंकि हमेशा एक छिपी हुई फ़ाइल का संचालन करने की क्षमता हो सकती है अपलोड किए गए फ़ोल्डर का उपयोग। खासतौर पर अगर फोल्डर डॉक्यूमेंट पर फुल हो तो कई हिस्सों में बंट जाता है जैसे कि फाइनल कट फाइल हो सकती है।
चार्ल्स जॉन थॉम्पसन III

कार्यक्षेत्र से असहमत: यह कुछ लोगों के लिए असंगतता का कारण है, जिसे बहुत से लोग करना चाहते हैं, इसलिए इसे निर्दिष्ट किया जाना चाहिए।
सिरो सेंटिल्ली 郝海东 i iro i 法轮功 '

10

अब आप डायरेक्टरी को ड्रैग एंड ड्रॉप और इनपुट दोनों के साथ अपलोड कर सकते हैं।

<input type='file' webkitdirectory >

और खींचें और ड्रॉप के लिए (वेबकिट ब्राउज़र के लिए)।

फ़ोल्डर्स को ड्रैग और ड्रॉप करना।

<div id="dropzone"></div>
<script>
var dropzone = document.getElementById('dropzone');
dropzone.ondrop = function(e) {
  var length = e.dataTransfer.items.length;
  for (var i = 0; i < length; i++) {
    var entry = e.dataTransfer.items[i].webkitGetAsEntry();
    if (entry.isFile) {
      ... // do whatever you want
    } else if (entry.isDirectory) {
      ... // do whatever you want
    }
  }
};
</script>

संसाधन:

http://updates.html5rocks.com/2012/07/Drag-and-drop-a-folder-onto-Chrome-now-available


1
क्या संपीड़ित फ़ोल्डरों का उपयोग किए बिना डाउनलोड करने के लिए ऐसा करना संभव है?
user2284570

8

फ़ायरफ़ॉक्स अब 15 नवंबर, 2016 को v50.0 में फ़ोल्डर अपलोड का समर्थन करता है: https://developer.mozilla.org/en-US/Firefox/Releases/50#Files_and_directories

आप फ़ायरफ़ॉक्स में फ़ोल्डरों को खींच सकते हैं और छोड़ सकते हैं या अपलोड करने के लिए ब्राउज़ कर सकते हैं और एक स्थानीय फ़ोल्डर चुन सकते हैं। यह सबफ़ोल्डर में नेस्टेड फ़ोल्डर का भी समर्थन करता है।

इसका मतलब है कि अब आप फ़ोल्डरों को अपलोड करने के लिए क्रोम, फ़ायरफ़ॉक्स, एज या ओपेरा का उपयोग कर सकते हैं। आप वर्तमान में Safari या Internet Explorer का उपयोग नहीं कर सकते हैं।


3

फ़ाइल और निर्देशिका प्रविष्टियों का उपयोग कैसे करें एपीआई का एक पूरा उदाहरण यहां दिया गया है :

var dropzone = document.getElementById("dropzone");
var listing = document.getElementById("listing");

function scanAndLogFiles(item, container) {
  var elem = document.createElement("li");
  elem.innerHTML = item.name;
  container.appendChild(elem);

  if (item.isDirectory) {
    var directoryReader = item.createReader();
    var directoryContainer = document.createElement("ul");
    container.appendChild(directoryContainer);

    directoryReader.readEntries(function(entries) {
      entries.forEach(function(entry) {
        scanAndLogFiles(entry, directoryContainer);
      });
    });
  }
}

dropzone.addEventListener(
  "dragover",
  function(event) {
    event.preventDefault();
  },
  false
);

dropzone.addEventListener(
  "drop",
  function(event) {
    var items = event.dataTransfer.items;

    event.preventDefault();
    listing.innerHTML = "";

    for (var i = 0; i < items.length; i++) {
      var item = items[i].webkitGetAsEntry();

      if (item) {
        scanAndLogFiles(item, listing);
      }
    }
  },
  false
);
body {
  font: 14px "Arial", sans-serif;
}

#dropzone {
  text-align: center;
  width: 300px;
  height: 100px;
  margin: 10px;
  padding: 10px;
  border: 4px dashed red;
  border-radius: 10px;
}

#boxtitle {
  display: table-cell;
  vertical-align: middle;
  text-align: center;
  color: black;
  font: bold 2em "Arial", sans-serif;
  width: 300px;
  height: 100px;
}
<p>Drag files and/or directories to the box below!</p>

<div id="dropzone">
  <div id="boxtitle">
    Drop Files Here
  </div>
</div>

<h2>Directory tree:</h2>

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

webkitGetAsEntry क्रोम 13+, फ़ायरफ़ॉक्स 50+ और एज द्वारा समर्थित है।

स्रोत: https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItem/webkitGetAsEntry


1
बढ़िया काम कर रहा है। Vue jsfiddle.net/KimNyholm/xua9kLny पर
पोर्ट किया गया

1

क्या HTML5 फ़ोल्डर्स या फ़ोल्डर ट्री के ड्रैग-ड्रॉप अपलोड की अनुमति देता है?

केवल क्रोम इस सुविधा का समर्थन करता है। यह किसी भी कर्षण के लिए विफल रहा है और इसे हटाए जाने की संभावना है।

रेफरी: https://developer.mozilla.org/en/docs/Web/API/DirectoryReader###Ebries


वाह। उस लिंक पर W3C नोट से बताना, यह वास्तव में जारी नहीं है। इस धारणा का आधार क्या है कि यह किसी भी कर्षण को प्राप्त करने में विफल रहा है?
12

@bebbi कोई अन्य ब्राउज़र विक्रेताओं ने इसे लागू नहीं किया
बेसराट

1
@ PabloBarríaUrenda टिप्पणी सच नहीं है; उनके मुद्दे पर उनके सवाल का जिक्र किया जा रहा है: stackoverflow.com/questions/51850469/… जिसे उन्होंने हल किया / महसूस readEntriesनहीं किया जा सकता है अगर कोई अन्य कॉल readEntriesअभी भी चलाया जा रहा है। DirectoryReader एपीआई डिजाइन सबसे अच्छा नहीं है
xlm

@xlm हाँ, वास्तव में आप सही हैं। मैंने इसे पोस्ट किया था जब मैं खुद इस मुद्दे पर हैरान था, लेकिन मैंने अंततः इसे हल कर दिया (और इस टिप्पणी के बारे में भूल गया)। मैंने अब भ्रामक टिप्पणी हटा दी है।
पाब्लो बैरिया उरेंडा

1

अद्यतन: 2012 के बाद से बहुत कुछ बदल गया है, इसके बजाय उत्तर देखें। मैं इस उत्तर को पुरातत्व की खातिर यहाँ छोड़ता हूँ।

HTML5 कल्पना यह नहीं कहती है कि अपलोड के लिए एक फ़ोल्डर का चयन करते समय, ब्राउज़र को सभी निहित फ़ाइलों को पुन: अपलोड करना चाहिए।

दरअसल, क्रोम / क्रोमियम में, आप एक फ़ोल्डर अपलोड कर सकते हैं, लेकिन जब आप ऐसा करते हैं, तो यह केवल एक अर्थहीन 4KB फाइल अपलोड करता है, जो निर्देशिका का प्रतिनिधित्व करता है। अल्फ़्रेस्को जैसे कुछ सर्वर-साइड एप्लिकेशन इसका पता लगा सकते हैं, और उपयोगकर्ता को चेतावनी दे सकते हैं कि फ़ोल्डर अपलोड नहीं किए जा सकते हैं:

निम्नलिखित अपलोड नहीं किए जा सकते क्योंकि वे या तो फ़ोल्डर हैं या आकार में शून्य बाइट्स हैं: अपरिभाषित


@ यूएमबी: शायद यह किसी तरह का पॉइंटर है। लेकिन चूंकि वास्तविक फ़ाइल क्लाइंट मशीन पर है, इसलिए सर्वर मशीन इस सूचक के साथ कुछ भी करने में सक्षम नहीं होगी, ज़ाहिर है।
निकोलस राउल

1

हाल ही में मेरी दो परियोजनाओं में इसे लागू करने की आवश्यकता पर अड़ गए हैं इसलिए मैंने इसके साथ मदद करने के लिए उपयोगिता कार्यों का एक समूह बनाया।

एक एक डेटा-संरचना बनाता है जो सभी फ़ोल्डरों, फाइलों और उनके बीच के संबंधों का प्रतिनिधित्व करता है, जैसे कि structure

{
  folders: [
    {
      name: string,
      folders: Array,
      files: Array
    },
    /* ... */
  ],
  files: Array
}

जबकि दूसरा सिर्फ सभी फाइलों (सभी फ़ोल्डरों और सब-फ़ोल्डर्स में) का एक Array देता है।

यहां पैकेज का लिंक दिया गया है: https://www.npmjs.com/package/file-system-utils

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.