File System Access API: लोकल फ़ाइलों का ऐक्सेस आसान बनाना

फ़ाइल सिस्टम ऐक्सेस एपीआई, वेब ऐप्लिकेशन को उपयोगकर्ता के डिवाइस पर मौजूद फ़ाइलों और फ़ोल्डर में किए गए बदलावों को सीधे पढ़ने या सेव करने देता है.

File System Access API क्या है?

File System Access API (पहले इसे Native File System API के नाम से जाना जाता था और पहले इसे राइटेबल Files API कहा जाता था) की मदद से डेवलपर ऐसे बेहतरीन वेब ऐप्लिकेशन बना सकते हैं जो उपयोगकर्ता के लोकल डिवाइस पर मौजूद फ़ाइलों से इंटरैक्ट करते हैं. इनमें IDEs, फ़ोटो और वीडियो एडिटर, टेक्स्ट एडिटर वगैरह शामिल हैं. किसी उपयोगकर्ता को वेब ऐप्लिकेशन का ऐक्सेस देने के बाद, यह एपीआई उन्हें बदलावों को सीधे उपयोगकर्ता के डिवाइस पर मौजूद फ़ाइलों और फ़ोल्डर में पढ़ने या सेव करने देता है. File System Access API, फ़ाइलों को पढ़ने और लिखने के अलावा, डायरेक्ट्री को भी खोल सकता है. साथ ही, इसके कॉन्टेंट की सूची बना सकता है.

अगर आपने पहले फ़ाइलें पढ़ने और लिखने का काम किया है, तो मैं आपको जो जानकारी शेयर करने जा रही हूं उसका ज़्यादातर से जाना आपको याद रहेगा. मेरी सलाह है कि आप इसे फिर भी पढ़ें, क्योंकि सभी सिस्टम एक जैसे नहीं होते.

फ़िलहाल, File System Access API, Windows, macOS, ChromeOS, और Linux पर मौजूद ज़्यादातर Chromium ब्राउज़र पर काम करता है. ध्यान देने लायक अपवाद है ब्रेव है, जहां यह फ़िलहाल सिर्फ़ फ़्लैग के पीछे उपलब्ध है. Chromium 109 और इसके बाद के वर्शन में, Android एपीआई के ऑरिजिन निजी फ़ाइल सिस्टम वाले हिस्से के साथ काम करता है. फ़िलहाल, पिकर तरीकों के लिए कोई योजना नहीं है. हालांकि, crbug.com/1011535 पर स्टार के निशान लगाकर, संभावित प्रोग्रेस को ट्रैक किया जा सकता है.

File System Access API का इस्तेमाल करना

File System Access API की क्षमता और उपयोगिता दिखाने के लिए, मैंने एक ही फ़ाइल टेक्स्ट एडिटर लिखी है. इससे आपको कोई टेक्स्ट फ़ाइल खोलने, उसमें बदलाव करने, बदलावों को डिस्क में वापस सेव करने या नई फ़ाइल शुरू करने और बदलावों को डिस्क में सेव करने का विकल्प मिलता है. यह कोई खास बात नहीं है, लेकिन इससे आपको कॉन्सेप्ट को समझने में मदद मिलती है.

ब्राउज़र समर्थन

ब्राउज़र सहायता

  • 86
  • 86
  • x
  • x

सोर्स

इसे आज़माएं

टेक्स्ट एडिटर डेमो में, File System Access API को इस्तेमाल करने का तरीका देखें.

लोकल फ़ाइल सिस्टम से कोई फ़ाइल पढ़ना

मुझे सबसे पहले उपयोगकर्ता को फ़ाइल चुनने और उसे डिस्क से पढ़ने के लिए कहना है.

उपयोगकर्ता को पढ़ने के लिए फ़ाइल चुनने को कहें

File System Access API का एंट्री पॉइंट window.showOpenFilePicker() है. कॉल करने पर, यह एक फ़ाइल पिकर डायलॉग बॉक्स दिखाता है. साथ ही, उपयोगकर्ता को फ़ाइल चुनने का प्रॉम्प्ट देता है. फ़ाइल चुनने के बाद, एपीआई फ़ाइल हैंडल का कलेक्शन दिखाता है. वैकल्पिक options पैरामीटर की मदद से, फ़ाइल पिकर के काम करने के तरीके पर असर डाला जा सकता है. उदाहरण के लिए, उपयोगकर्ता को कई फ़ाइलें, डायरेक्ट्री या अलग-अलग तरह की फ़ाइलें चुनने की अनुमति देकर. किसी विकल्प के बिना, फ़ाइल पिकर की मदद से उपयोगकर्ता एक फ़ाइल चुन सकता है. यह टेक्स्ट एडिटर के लिए सबसे सही है.

कई अन्य दमदार एपीआई की तरह, showOpenFilePicker() को सुरक्षित कॉन्टेक्स्ट में कॉल किया जाना चाहिए. साथ ही, इसे उपयोगकर्ता के जेस्चर में ही कॉल किया जाना चाहिए.

let fileHandle;
butOpenFile.addEventListener('click', async () => {
  // Destructure the one-element array.
  [fileHandle] = await window.showOpenFilePicker();
  // Do something with the file handle.
});

जब उपयोगकर्ता कोई फ़ाइल चुनता है, तो showOpenFilePicker() हैंडल का कलेक्शन दिखाता है. इस मामले में, एक एलिमेंट वाला कलेक्शन, जिसमें एक FileSystemFileHandle होता है. इसमें, फ़ाइल से इंटरैक्ट करने के लिए ज़रूरी प्रॉपर्टी और तरीके शामिल होते हैं.

फ़ाइल हैंडल का रेफ़रंस रखना बेहतर रहता है, ताकि इसे बाद में इस्तेमाल किया जा सके. उसे फ़ाइल में किए गए बदलावों को सेव करना होगा या फ़ाइल से जुड़ी कोई दूसरी कार्रवाई करनी होगी.

फ़ाइल सिस्टम से कोई फ़ाइल पढ़ना

अब आपके पास फ़ाइल का हैंडल है, तो आप फ़ाइल की प्रॉपर्टी पा सकते हैं या फ़ाइल को खुद ऐक्सेस कर सकते हैं. फ़िलहाल, मैं इसके कॉन्टेंट को पढ़ूँगी. handle.getFile() को कॉल करने से, File ऑब्जेक्ट मिलता है, जिसमें एक ब्लॉब होता है. ब्लॉब से डेटा पाने के लिए, इसके तरीकों में से किसी एक को कॉल करें (slice(), stream(), text(), arrayBuffer()).

const file = await fileHandle.getFile();
const contents = await file.text();

FileSystemFileHandle.getFile() से मिले File ऑब्जेक्ट को सिर्फ़ तब तक पढ़ा जा सकता है, जब तक डिस्क पर मौजूद फ़ाइल में कोई बदलाव नहीं किया जाता. अगर डिस्क पर मौजूद फ़ाइल में बदलाव किया जाता है, तो File ऑब्जेक्ट को पढ़ा नहीं जा सकता. साथ ही, बदले गए डेटा को पढ़ने के लिए, आपको नया File ऑब्जेक्ट पाने के लिए, getFile() को फिर से कॉल करना होगा.

यह रही पूरी जानकारी

जब उपयोगकर्ता 'खोलें' बटन पर क्लिक करते हैं, तो ब्राउज़र एक फ़ाइल पिकर दिखाता है. जब वे कोई फ़ाइल चुन लेते हैं, तो ऐप्लिकेशन कॉन्टेंट को पढ़ता है और उन्हें <textarea> में डाल देता है.

let fileHandle;
butOpenFile.addEventListener('click', async () => {
  [fileHandle] = await window.showOpenFilePicker();
  const file = await fileHandle.getFile();
  const contents = await file.text();
  textArea.value = contents;
});

फ़ाइल को लोकल फ़ाइल सिस्टम में लिखें

टेक्स्ट एडिटर में, फ़ाइल को सेव करने के दो तरीके हैं: सेव करें और इस रूप में सेव करें. Save, पहले मिले फ़ाइल हैंडल का इस्तेमाल करके बदलावों को सिर्फ़ ओरिजनल फ़ाइल में लिख देता है. हालांकि, इस रूप में सेव करें से एक नई फ़ाइल बनती है और इसलिए उसके लिए एक नया फ़ाइल हैंडल होना ज़रूरी है.

नई फ़ाइल बनाएं

किसी फ़ाइल को सेव करने के लिए, showSaveFilePicker() को कॉल करें, जो फ़ाइल पिकर को "सेव करें" मोड में दिखाता है. इससे उपयोगकर्ता वह नई फ़ाइल चुन सकता है जिसे उसे सेव करने के लिए इस्तेमाल करना है. टेक्स्ट एडिटर के लिए, मैं चाहता था कि यह अपने-आप .txt एक्सटेंशन जोड़ दे. इसलिए, मैंने कुछ और पैरामीटर जोड़ दिए हैं.

async function getNewFileHandle() {
  const options = {
    types: [
      {
        description: 'Text Files',
        accept: {
          'text/plain': ['.txt'],
        },
      },
    ],
  };
  const handle = await window.showSaveFilePicker(options);
  return handle;
}

डिस्क पर बदलाव सेव करें

आपको फ़ाइल में किए गए बदलावों को सेव करने के लिए, GitHub पर मेरे टेक्स्ट एडिटर डेमो में सभी कोड मिल जाएंगे. फ़ाइल सिस्टम के मुख्य इंटरैक्शन, fs-helpers.js में दिए गए हैं. सबसे आसान तरीके में, यह प्रोसेस नीचे दिए गए कोड की तरह दिखती है. मैं हर चरण के बारे में बताऊँगी और उसे विस्तार से समझाऊँगी.

// fileHandle is an instance of FileSystemFileHandle..
async function writeFile(fileHandle, contents) {
  // Create a FileSystemWritableFileStream to write to.
  const writable = await fileHandle.createWritable();
  // Write the contents of the file to the stream.
  await writable.write(contents);
  // Close the file and write the contents to disk.
  await writable.close();
}

डिस्क में डेटा लिखने के लिए, FileSystemWritableFileStream ऑब्जेक्ट का इस्तेमाल किया जाता है. यह WritableStream की एक सब-क्लास है. फ़ाइल हैंडल ऑब्जेक्ट पर, createWritable() को कॉल करके स्ट्रीम बनाएं. जब createWritable() को कॉल किया जाता है, तो ब्राउज़र सबसे पहले यह जांच करता है कि उपयोगकर्ता ने फ़ाइल में लिखने की अनुमति दी है या नहीं. अगर लिखने की अनुमति नहीं दी जाती है, तो ब्राउज़र उपयोगकर्ता को अनुमति के लिए अनुरोध करता है. अगर अनुमति नहीं दी जाती है, तो createWritable(), DOMException को फेंकता है और ऐप्लिकेशन, फ़ाइल में बदलाव नहीं कर पाएगा. टेक्स्ट एडिटर में, DOMException ऑब्जेक्ट को saveFile() तरीके से हैंडल किया जाता है.

write() तरीके में एक स्ट्रिंग होती है, जो टेक्स्ट एडिटर के लिए ज़रूरी है. हालांकि, यह BufferSource या Blob भी ले सकता है. उदाहरण के लिए, किसी स्ट्रीम को सीधे उस पर पाइप किया जा सकता है:

async function writeURLToFile(fileHandle, url) {
  // Create a FileSystemWritableFileStream to write to.
  const writable = await fileHandle.createWritable();
  // Make an HTTP request for the contents.
  const response = await fetch(url);
  // Stream the response into the file.
  await response.body.pipeTo(writable);
  // pipeTo() closes the destination pipe by default, no need to close it.
}

फ़ाइल को किसी खास पोज़िशन पर अपडेट करने या फ़ाइल का साइज़ बदलने के लिए, स्ट्रीम में seek() या truncate() भी किया जा सकता है.

सुझाए गए फ़ाइल नाम को तय करके और डायरेक्ट्री को शुरू करें

कई मामलों में, यह हो सकता है कि आप अपने ऐप्लिकेशन से, डिफ़ॉल्ट फ़ाइल के नाम या जगह की जानकारी का सुझाव देना चाहें. उदाहरण के लिए, हो सकता है कि कोई टेक्स्ट एडिटर, Untitled के बजाय Untitled Text.txt के डिफ़ॉल्ट फ़ाइल नाम का सुझाव देना चाहे. ऐसा करने के लिए, suggestedName प्रॉपर्टी को showSaveFilePicker विकल्पों के हिस्से के तौर पर पास करें.

const fileHandle = await self.showSaveFilePicker({
  suggestedName: 'Untitled Text.txt',
  types: [{
    description: 'Text documents',
    accept: {
      'text/plain': ['.txt'],
    },
  }],
});

डिफ़ॉल्ट स्टार्ट डायरेक्ट्री पर भी यही बात लागू होती है. अगर टेक्स्ट एडिटर बनाया जा रहा है, तो फ़ाइल सेव करने या फ़ाइल खोलने वाला डायलॉग बॉक्स डिफ़ॉल्ट documents फ़ोल्डर में शुरू किया जा सकता है. वहीं, इमेज एडिटर के लिए डिफ़ॉल्ट pictures फ़ोल्डर से इसकी शुरुआत की जा सकती है. आप showSaveFilePicker, showDirectoryPicker() या showOpenFilePicker जैसे तरीकों में startIn प्रॉपर्टी पास करके, डिफ़ॉल्ट स्टार्ट डायरेक्ट्री का सुझाव दे सकते हैं.

const fileHandle = await self.showOpenFilePicker({
  startIn: 'pictures'
});

लोकप्रिय सिस्टम डायरेक्ट्री की सूची यह है:

  • desktop: अगर ऐसी कोई चीज़ मौजूद है, तो उपयोगकर्ता की डेस्कटॉप डायरेक्ट्री.
  • documents: वह डायरेक्ट्री जिसमें उपयोगकर्ता के बनाए गए दस्तावेज़ आम तौर पर सेव किए जाते हैं.
  • downloads: वह डायरेक्ट्री जहां डाउनलोड की गई फ़ाइलें आम तौर पर स्टोर की जाती हैं.
  • music: वह डायरेक्ट्री जहां आम तौर पर ऑडियो फ़ाइलें सेव की जाती हैं.
  • pictures: वह डायरेक्ट्री जहां फ़ोटो और अन्य इमेज आम तौर पर सेव की जाती हैं.
  • videos: वह डायरेक्ट्री जहां आम तौर पर वीडियो/फ़िल्में सेव की जाती हैं.

जानी-मानी सिस्टम डायरेक्ट्री के अलावा, किसी मौजूदा फ़ाइल या डायरेक्ट्री हैंडल को भी startIn की वैल्यू के तौर पर पास किया जा सकता है. इसके बाद, डायलॉग उसी डायरेक्ट्री में खुलेगा.

// Assume `directoryHandle` is a handle to a previously opened directory.
const fileHandle = await self.showOpenFilePicker({
  startIn: directoryHandle
});

अलग-अलग फ़ाइल पिकर का मकसद बताना

कभी-कभी अलग-अलग कामों के लिए, ऐप्लिकेशन में अलग-अलग पिकर होते हैं. उदाहरण के लिए, एक रिच टेक्स्ट एडिटर, उपयोगकर्ता को टेक्स्ट फ़ाइलें खोलने के साथ-साथ इमेज इंपोर्ट करने की भी अनुमति दे सकता है. डिफ़ॉल्ट रूप से, हर फ़ाइल पिकर उस जगह पर खुलेगा जहां पिछली बार आपको याद रखा गया था. हर तरह के पिकर के लिए id वैल्यू सेव करके, इस समस्या से बचा जा सकता है. अगर id दिया गया है, तो फ़ाइल पिकर लागू करने पर, उस id के लिए पिछली बार इस्तेमाल की गई अलग डायरेक्ट्री को याद रखा जाता है.

const fileHandle1 = await self.showSaveFilePicker({
  id: 'openText',
});

const fileHandle2 = await self.showSaveFilePicker({
  id: 'importImage',
});

IndexedDB में, फ़ाइल हैंडल या डायरेक्ट्री हैंडल स्टोर करना

फ़ाइल और डायरेक्ट्री हैंडल, क्रम से लगाए जा सकते हैं. इसका मतलब है कि किसी फ़ाइल या डायरेक्ट्री हैंडल को IndexedDB पर सेव किया जा सकता है. इसके अलावा, postMessage() को कॉल करके, उन्हें एक ही टॉप लेवल ऑरिजिन के बीच भेजा जा सकता है.

IndexedDB में फ़ाइल या डायरेक्ट्री हैंडल सेव करने का मतलब है कि आप स्थिति को सेव कर सकते हैं या याद रख सकते हैं कि उपयोगकर्ता किन फ़ाइलों या डायरेक्ट्री पर काम कर रहा था. इसकी मदद से, हाल ही में खोली गई या बदलाव की गई फ़ाइलों की सूची सेव की जा सकती है. इसके अलावा, ऐप्लिकेशन खोले जाने पर पिछली फ़ाइल को फिर से खोलने, काम करने वाली पिछली डायरेक्ट्री को वापस लाने वगैरह जैसे काम किए जा सकते हैं. टेक्स्ट एडिटर में, मैं हाल ही में खोली गई पांच फ़ाइलों की एक सूची स्टोर करता हूं, जिन्हें उपयोगकर्ता ने खोला है. इससे उन फ़ाइलों को फिर से ऐक्सेस करना आसान हो जाता है.

नीचे दिए गए कोड का उदाहरण, फ़ाइल हैंडल और डायरेक्ट्री हैंडल को स्टोर करना और वापस पाना दिखाता है. इसे Glitch पर जाकर इस्तेमाल किया जा सकता है. (मैं कम शब्दों में जानकारी देने के लिए, idb-keyval लाइब्रेरी का इस्तेमाल करता/करती हूं.)

import { get, set } from 'https://unpkg.com/idb-keyval@5.0.2/dist/esm/index.js';

const pre1 = document.querySelector('pre.file');
const pre2 = document.querySelector('pre.directory');
const button1 = document.querySelector('button.file');
const button2 = document.querySelector('button.directory');

// File handle
button1.addEventListener('click', async () => {
  try {
    const fileHandleOrUndefined = await get('file');
    if (fileHandleOrUndefined) {
      pre1.textContent = `Retrieved file handle "${fileHandleOrUndefined.name}" from IndexedDB.`;
      return;
    }
    const [fileHandle] = await window.showOpenFilePicker();
    await set('file', fileHandle);
    pre1.textContent = `Stored file handle for "${fileHandle.name}" in IndexedDB.`;
  } catch (error) {
    alert(error.name, error.message);
  }
});

// Directory handle
button2.addEventListener('click', async () => {
  try {
    const directoryHandleOrUndefined = await get('directory');
    if (directoryHandleOrUndefined) {
      pre2.textContent = `Retrieved directroy handle "${directoryHandleOrUndefined.name}" from IndexedDB.`;
      return;
    }
    const directoryHandle = await window.showDirectoryPicker();
    await set('directory', directoryHandle);
    pre2.textContent = `Stored directory handle for "${directoryHandle.name}" in IndexedDB.`;
  } catch (error) {
    alert(error.name, error.message);
  }
});

सेव की गई फ़ाइल या डायरेक्ट्री के हैंडल और अनुमतियां

फ़िलहाल, दो सेशन के बीच अनुमतियां बरकरार नहीं हैं. इसलिए, आपको यह पुष्टि करनी चाहिए कि उपयोगकर्ता ने queryPermission() का इस्तेमाल करके, फ़ाइल या डायरेक्ट्री को अनुमति दी है या नहीं. अगर अनुमति नहीं मिली है, तो requestPermission() को कॉल करके (फिर से) अनुरोध करें. यह फ़ाइल और डायरेक्ट्री हैंडल के लिए भी इसी तरह काम करता है. आपको fileOrDirectoryHandle.requestPermission(descriptor) या fileOrDirectoryHandle.queryPermission(descriptor) को चलाना होगा.

टेक्स्ट एडिटर में, मैंने एक verifyPermission() तरीका बनाया था, जो यह देखता है कि उपयोगकर्ता ने पहले अनुमति दी है या नहीं. साथ ही, ज़रूरी होने पर अनुरोध करता है.

async function verifyPermission(fileHandle, readWrite) {
  const options = {};
  if (readWrite) {
    options.mode = 'readwrite';
  }
  // Check if permission was already granted. If so, return true.
  if ((await fileHandle.queryPermission(options)) === 'granted') {
    return true;
  }
  // Request permission. If the user grants permission, return true.
  if ((await fileHandle.requestPermission(options)) === 'granted') {
    return true;
  }
  // The user didn't grant permission, so return false.
  return false;
}

कॉन्टेंट पढ़ने के अनुरोध के साथ लिखने की अनुमति मांगने का मतलब है कि मैंने अनुमति के प्रॉम्प्ट की संख्या कम कर दी है. फ़ाइल खोलने पर, उपयोगकर्ता को एक प्रॉम्प्ट दिखता है और वह फ़ाइल को पढ़ने और उसमें बदलाव करने, दोनों को अनुमति देता है.

किसी डायरेक्ट्री को खोलना और उसके कॉन्टेंट की सूची बनाना

किसी डायरेक्ट्री में मौजूद सभी फ़ाइलों की गिनती करने के लिए, showDirectoryPicker() को कॉल करें. उपयोगकर्ता, पिकर में एक डायरेक्ट्री चुनता है. इसके बाद FileSystemDirectoryHandle दिखता है. इससे, डायरेक्ट्री की फ़ाइलों की गिनती और उन्हें ऐक्सेस किया जा सकता है. डिफ़ॉल्ट रूप से, आपके पास डायरेक्ट्री में मौजूद फ़ाइलों को पढ़ने का ऐक्सेस होगा. हालांकि, अगर आपको लिखने का ऐक्सेस चाहिए, तो इस तरीके में { mode: 'readwrite' } पास किया जा सकता है.

const butDir = document.getElementById('butDirectory');
butDir.addEventListener('click', async () => {
  const dirHandle = await window.showDirectoryPicker();
  for await (const entry of dirHandle.values()) {
    console.log(entry.kind, entry.name);
  }
});

उदाहरण के लिए, अगर आपको अलग-अलग फ़ाइल साइज़ पाने के लिए getFile() से हर फ़ाइल को ऐक्सेस करना है, तो हर नतीजे पर एक के बाद एक await का इस्तेमाल न करें. इसके बजाय, सभी फ़ाइलों को एक साथ प्रोसेस करें, उदाहरण के लिए, Promise.all() के ज़रिए.

const butDir = document.getElementById('butDirectory');
butDir.addEventListener('click', async () => {
  const dirHandle = await window.showDirectoryPicker();
  const promises = [];
  for await (const entry of dirHandle.values()) {
    if (entry.kind !== 'file') {
      continue;
    }
    promises.push(entry.getFile().then((file) => `${file.name} (${file.size})`));
  }
  console.log(await Promise.all(promises));
});

किसी डायरेक्ट्री में फ़ाइलें और फ़ोल्डर बनाना या उन्हें ऐक्सेस करना

किसी डायरेक्ट्री से, getFileHandle() या getDirectoryHandle() तरीके का इस्तेमाल करके, फ़ाइलें और फ़ोल्डर बनाए जा सकते हैं या उन्हें ऐक्सेस किया जा सकता है. create की कुंजी और true या false की बूलियन वैल्यू के साथ एक वैकल्पिक options ऑब्जेक्ट पास करके, यह तय किया जा सकता है कि नई फ़ाइल या फ़ोल्डर मौजूद न होने पर क्या बनाया जाना चाहिए.

// In an existing directory, create a new directory named "My Documents".
const newDirectoryHandle = await existingDirectoryHandle.getDirectoryHandle('My Documents', {
  create: true,
});
// In this new directory, create a file named "My Notes.txt".
const newFileHandle = await newDirectoryHandle.getFileHandle('My Notes.txt', { create: true });

किसी डायरेक्ट्री में मौजूद किसी आइटम के पाथ का समाधान करना

किसी डायरेक्ट्री में, फ़ाइलों या फ़ोल्डर के साथ काम करते समय, उस आइटम के पाथ को हल करना मददगार हो सकता है. ऐसा, अपने नाम resolve() वाले तरीके का इस्तेमाल करके किया जा सकता है. समस्या हल करने के लिए, कोई आइटम, डायरेक्ट या इनडायरेक्ट चाइल्ड डायरेक्ट्री का हो सकता है.

// Resolve the path of the previously created file called "My Notes.txt".
const path = await newDirectoryHandle.resolve(newFileHandle);
// `path` is now ["My Documents", "My Notes.txt"]

किसी डायरेक्ट्री से फ़ाइलें और फ़ोल्डर मिटाना

अगर आपको किसी डायरेक्ट्री का ऐक्सेस मिला है, तो removeEntry() तरीके का इस्तेमाल करके उसमें शामिल फ़ाइलों और फ़ोल्डर को मिटाया जा सकता है. फ़ोल्डर को मिटाने का अनुरोध बार-बार किया जा सकता है. इसमें सभी सब-फ़ोल्डर और उनमें मौजूद फ़ाइलें शामिल की जा सकती हैं.

// Delete a file.
await directoryHandle.removeEntry('Abandoned Projects.txt');
// Recursively delete a folder.
await directoryHandle.removeEntry('Old Stuff', { recursive: true });

किसी फ़ाइल या फ़ोल्डर को सीधे मिटाना

अगर आपके पास किसी फ़ाइल या डायरेक्ट्री हैंडल का ऐक्सेस है, तो उसे हटाने के लिए, remove() को FileSystemFileHandle या FileSystemDirectoryHandle पर कॉल करें.

// Delete a file.
await fileHandle.remove();
// Delete a directory.
await directoryHandle.remove();

फ़ाइलों और फ़ोल्डर के नाम बदलना और उन्हें दूसरी जगह ले जाना

FileSystemHandle इंटरफ़ेस पर move() को कॉल करके, फ़ाइलों और फ़ोल्डर का नाम बदला जा सकता है या उन्हें नई जगह पर ले जाया जा सकता है. FileSystemHandle में चाइल्ड इंटरफ़ेस FileSystemFileHandle और FileSystemDirectoryHandle हैं. move() वाले तरीके में एक या दो पैरामीटर लगते हैं. पहला विकल्प या तो नए नाम वाली स्ट्रिंग हो सकती है या डेस्टिनेशन फ़ोल्डर के लिए FileSystemDirectoryHandle हो सकती है. बाद वाले मामले में, वैकल्पिक दूसरा पैरामीटर नए नाम वाली एक स्ट्रिंग होती है, इसलिए ले जाने और नाम बदलने का काम एक ही चरण में हो सकता है.

// Rename the file.
await file.move('new_name');
// Move the file to a new directory.
await file.move(directory);
// Move the file to a new directory and rename it.
await file.move(directory, 'newer_name');

इंटिग्रेशन को खींचें और छोड़ें

एचटीएमएल खींचें और छोड़ें इंटरफ़ेस की मदद से वेब ऐप्लिकेशन, किसी वेब पेज पर खींची गई और छोड़ी गई फ़ाइलों को स्वीकार कर सकते हैं. 'खींचें और छोड़ें' कार्रवाई के दौरान, ड्रैग की गई फ़ाइल और डायरेक्ट्री आइटम, फ़ाइल और डायरेक्ट्री एंट्री के साथ जुड़े होते हैं. अगर खींचा गया आइटम कोई फ़ाइल है, तो DataTransferItem.getAsFileSystemHandle() तरीका, FileSystemFileHandle ऑब्जेक्ट के साथ प्रॉमिस दिखाता है. साथ ही, अगर खींचा गया आइटम कोई डायरेक्ट्री है, तो FileSystemDirectoryHandle ऑब्जेक्ट के साथ वादा करता है. नीचे दी गई सूची में इसे दिखाया गया है. ध्यान दें कि'खींचें और छोड़ें' इंटरफ़ेस का DataTransferItem.kind, और दोनों फ़ाइलों के लिए "file" है. वहीं, फ़ाइल सिस्टम ऐक्सेस एपीआई का FileSystemHandle.kind, फ़ाइलों के लिए "file" और डायरेक्ट्री के लिए "directory" है.

elem.addEventListener('dragover', (e) => {
  // Prevent navigation.
  e.preventDefault();
});

elem.addEventListener('drop', async (e) => {
  e.preventDefault();

  const fileHandlesPromises = [...e.dataTransfer.items]
    .filter((item) => item.kind === 'file')
    .map((item) => item.getAsFileSystemHandle());

  for await (const handle of fileHandlesPromises) {
    if (handle.kind === 'directory') {
      console.log(`Directory: ${handle.name}`);
    } else {
      console.log(`File: ${handle.name}`);
    }
  }
});

ऑरिजिन का निजी फ़ाइल सिस्टम ऐक्सेस करना

ऑरिजिन निजी फ़ाइल सिस्टम, स्टोरेज एंडपॉइंट होता है. जैसा कि नाम से ही पता चलता है, यह पेज के ऑरिजिन से ही निजी होता है. आम तौर पर, ब्राउज़र इस ऑरिजिन वाले निजी फ़ाइल सिस्टम के कॉन्टेंट को कहीं भी डिस्क में सेव करके रखते हैं. हालांकि, ऐसा नहीं होता कि कॉन्टेंट को उपयोगकर्ता आसानी से ऐक्सेस कर सके. इसी तरह, ऐसी कोई उम्मीद नहीं है कि जिन फ़ाइलों या डायरेक्ट्री के नाम, ऑरिजिन निजी फ़ाइल सिस्टम के बच्चों के नाम से मेल खाते हैं वे मौजूद होंगी. अंदरूनी तौर पर ब्राउज़र को ऐसा लग सकता है कि ये फ़ाइलें हैं, क्योंकि यह एक निजी फ़ाइल सिस्टम है. ब्राउज़र इन "फ़ाइलों" को किसी डेटाबेस या किसी दूसरे डेटा स्ट्रक्चर में सेव कर सकता है. अगर इस एपीआई का इस्तेमाल किया जाता है, तो यह उम्मीद करें कि बनाई गई फ़ाइलें, हार्ड डिस्क पर वन-टू-वन से मेल खाती हों. रूट FileSystemDirectoryHandle का ऐक्सेस मिलने के बाद, ऑरिजिन निजी फ़ाइल सिस्टम पर आम तौर पर इस्तेमाल किया जा सकता है.

const root = await navigator.storage.getDirectory();
// Create a new file handle.
const fileHandle = await root.getFileHandle('Untitled.txt', { create: true });
// Create a new directory handle.
const dirHandle = await root.getDirectoryHandle('New Folder', { create: true });
// Recursively remove a directory.
await root.removeEntry('Old Stuff', { recursive: true });

ब्राउज़र सहायता

  • 86
  • 86
  • 111
  • 78 जीबी में से

सोर्स

ऑरिजिन निजी फ़ाइल सिस्टम से, परफ़ॉर्मेंस के लिए ऑप्टिमाइज़ की गई फ़ाइलों को ऐक्सेस करना

ऑरिजिन निजी फ़ाइल सिस्टम, एक ऐसी खास तरह की फ़ाइल का ऐक्सेस देता है जो बेहतर तरीके से काम करती है. उदाहरण के लिए, फ़ाइल के कॉन्टेंट को फ़ाइल सिस्टम में सेव करने और लिखने का खास ऐक्सेस देना. Chromium 102 और इसके बाद के वर्शन में, फ़ाइल के ऐक्सेस को आसान बनाने के लिए ऑरिजिन निजी फ़ाइल सिस्टम पर एक और तरीका दिया गया है: createSyncAccessHandle() (सिंक्रोनस रीड और राइट ऐक्शन के लिए). यह FileSystemFileHandle पर दिखता है, लेकिन खास तौर पर वेब वर्कर में.

// (Read and write operations are synchronous,
// but obtaining the handle is asynchronous.)
// Synchronous access exclusively in Worker contexts.
const accessHandle = await fileHandle.createSyncAccessHandle();
const writtenBytes = accessHandle.write(buffer);
const readBytes = accessHandle.read(buffer, { at: 1 });

पॉलीफ़िलिंग

File System Access API के तरीकों को पूरी तरह से पॉलीफ़िल नहीं किया जा सकता.

  • showOpenFilePicker() तरीके को <input type="file"> एलिमेंट से अनुमान लगाया जा सकता है.
  • showSaveFilePicker() तरीके को <a download="file_name"> एलिमेंट के साथ सिम्युलेट किया जा सकता है. हालांकि, इससे प्रोग्राम के हिसाब से, अपने-आप होने वाली प्रोसेस शुरू हो जाती है और मौजूदा फ़ाइलों को ओवरराइट करने की अनुमति नहीं मिलती.
  • showDirectoryPicker() वाले तरीके को, नॉन-स्टैंडर्ड <input type="file" webkitdirectory> एलिमेंट के साथ एम्युलेट किया जा सकता है.

हमने ब्राउज़र-fs-access नाम की एक लाइब्रेरी बनाई है. यह जहां भी संभव हो, File System Access API का इस्तेमाल करती है. बाकी सभी मामलों में, यह सबसे सही विकल्प पर वापस आती है.

सुरक्षा और अनुमतियां

Chrome टीम ने मज़बूत वेब प्लैटफ़ॉर्म सुविधाओं का ऐक्सेस कंट्रोल करना में बताए गए मुख्य सिद्धांतों का इस्तेमाल करके, File System Access API को डिज़ाइन और लागू किया है. इन सिद्धांतों में, उपयोगकर्ता कंट्रोल और पारदर्शिता, और उपयोगकर्ता की सुविधाओं का इस्तेमाल करना शामिल है.

कोई फ़ाइल खोलना या नई फ़ाइल सेव करना

पढ़ने के लिए फ़ाइल खोलने के लिए, फ़ाइल पिकर
इस टूल का इस्तेमाल करके, किसी मौजूदा फ़ाइल को पढ़ने के लिए खोला जा सकता है.

कोई फ़ाइल खोलते समय उपयोगकर्ता, फ़ाइल पिकर की मदद से फ़ाइल या डायरेक्ट्री को पढ़ने की अनुमति देता है. खुले हुए फ़ाइल पिकर को उपयोगकर्ता के जेस्चर से सिर्फ़ तब दिखाया जा सकता है, जब उसे सुरक्षित कॉन्टेक्स्ट से दिखाया गया हो. अगर उपयोगकर्ता अपना इरादा बदल देते हैं, तो वे फ़ाइल पिकर में चुने गए विकल्प को रद्द कर सकते हैं. इससे साइट को किसी भी चीज़ का ऐक्सेस नहीं मिलेगा. यह <input type="file"> एलिमेंट के जैसा ही है.

किसी फ़ाइल को डिस्क पर सेव करने के लिए, फ़ाइल पिकर.
किसी फ़ाइल को डिस्क पर सेव करने के लिए इस्तेमाल किया जाने वाला फ़ाइल पिकर.

इसी तरह, जब कोई वेब ऐप्लिकेशन किसी नई फ़ाइल को सेव करना चाहता है, तो ब्राउज़र सेव फ़ाइल पिकर दिखाता है, ताकि उपयोगकर्ता नई फ़ाइल का नाम और जगह बता सके. फ़ाइल पिकर, ऐप्लिकेशन को डिवाइस पर नई फ़ाइल सेव करने और मौजूदा फ़ाइल को ओवरराइट करने की अनुमति देता है. इसलिए, फ़ाइल पिकर ऐप्लिकेशन को फ़ाइल पर कुछ लिखने की अनुमति देता है.

पाबंदी वाले फ़ोल्डर

उपयोगकर्ताओं और उनके डेटा को सुरक्षित रखने के लिए, ब्राउज़र कुछ खास फ़ोल्डर में डेटा सेव करने के विकल्प को सीमित कर सकता है. उदाहरण के लिए, Windows जैसे मुख्य ऑपरेटिंग सिस्टम फ़ोल्डर, macOS Library फ़ोल्डर वगैरह. ऐसा होने पर, ब्राउज़र एक प्रॉम्प्ट दिखाता है और उपयोगकर्ता से कोई दूसरा फ़ोल्डर चुनने के लिए कहता है.

किसी मौजूदा फ़ाइल या डायरेक्ट्री में बदलाव करना

कोई वेब ऐप्लिकेशन, उपयोगकर्ता की अनुमति के बिना, डिस्क पर मौजूद किसी फ़ाइल में बदलाव नहीं कर सकता.

अनुमति का प्रॉम्प्ट

अगर कोई व्यक्ति किसी ऐसी फ़ाइल में बदलाव सेव करना चाहता है जिसे उसने पहले पढ़ने का ऐक्सेस दिया था, तो ब्राउज़र, अनुमति का अनुरोध दिखाता है. इसमें, साइट को डिस्क में बदलाव करने की अनुमति मांगी जाती है. अनुमति का अनुरोध, सिर्फ़ उपयोगकर्ता के जेस्चर से ट्रिगर किया जा सकता है. उदाहरण के लिए, 'सेव करें' बटन पर क्लिक करना.

फ़ाइल सेव करने से पहले, अनुमति का प्रॉम्प्ट दिखेगा.
ब्राउज़र को किसी मौजूदा फ़ाइल पर लिखने की अनुमति देने से पहले, उपयोगकर्ताओं को दिखने वाला प्रॉम्प्ट.

इसके अलावा, कोई वेब ऐप्लिकेशन जो कई फ़ाइलों में बदलाव करता है, जैसे कि IDE, वह ऐप्लिकेशन खोलने पर बदलावों को सेव करने के लिए अनुमति भी मांग सकता है.

अगर उपयोगकर्ता 'रद्द करें' चुनता है और लिखने का ऐक्सेस नहीं देता है, तो वेब ऐप्लिकेशन उन बदलावों को लोकल फ़ाइल में सेव नहीं कर सकता. इसे उपयोगकर्ता को अपना डेटा सेव करने का एक वैकल्पिक तरीका देना चाहिए, जैसे कि फ़ाइल को"डाउनलोड" करने का तरीका देना, डेटा को क्लाउड पर सेव करना वगैरह.

पारदर्शिता

खोज बार (खोज क्वेरी डालने वाला बार) का आइकॉन
खोज बार (खोज क्वेरी डालने वाला बार) आइकॉन से पता चलता है कि उपयोगकर्ता ने वेबसाइट को लोकल फ़ाइल में सेव करने की अनुमति दी है.

वेब ऐप्लिकेशन को लोकल फ़ाइल सेव करने की अनुमति देने के बाद, ब्राउज़र यूआरएल बार में एक आइकॉन दिखाता है. आइकॉन पर क्लिक करने पर, एक पॉप-ओवर खुलता है. इस पॉप-ओवर में उन फ़ाइलों की सूची दिखती है जिनका ऐक्सेस उपयोगकर्ता ने दिया है. उपयोगकर्ता चाहें, तो उस ऐक्सेस को आसानी से रद्द कर सकते हैं.

अनुमति का बने रहना

वेब ऐप्लिकेशन, सूचना दिए बिना फ़ाइल में किए गए बदलावों को तब तक सेव कर सकता है, जब तक कि उसके मूल टैब को बंद नहीं कर दिया जाता. टैब बंद होने के बाद, साइट के पास किसी भी तरह का ऐक्सेस नहीं रहता. अगली बार जब उपयोगकर्ता वेब ऐप्लिकेशन का इस्तेमाल करेगा, तो उसे फ़ाइलों को ऐक्सेस करने के लिए कहा जाएगा.

सुझाव/राय दें या शिकायत करें

हम फ़ाइल सिस्टम ऐक्सेस एपीआई के साथ आपके अनुभवों के बारे में जानना चाहते हैं.

हमें इस एपीआई के डिज़ाइन के बारे में बताएं

क्या एपीआई में ऐसा कुछ है जो आपकी उम्मीद के मुताबिक काम नहीं करता? या ऐसा नहीं है कि अपना आइडिया लागू करने के लिए, ऐसे तरीके या प्रॉपर्टी मौजूद नहीं हैं जिनकी ज़रूरत आपको है? क्या सुरक्षा मॉडल के बारे में आपका कोई सवाल या टिप्पणी है?

  • WICG File System Access GitHub रेपो पर, कोई खास समस्या दर्ज करें या किसी मौजूदा समस्या पर अपने विचार जोड़ें.

क्या लागू करने में कोई समस्या है?

क्या आपको Chrome को लागू करने में कोई गड़बड़ी मिली? या क्या इसे लागू करने की प्रक्रिया खास जानकारी से अलग है?

  • https://new.crbug.com पर गड़बड़ी की शिकायत करें. जितना हो सके ज़्यादा से ज़्यादा जानकारी दें, पेज को फिर से बनाने के आसान निर्देश दें, और कॉम्पोनेंट को Blink>Storage>FileSystem पर सेट करें. Glitch का इस्तेमाल करके, तुरंत और आसान तरीकों को शेयर किया जा सकता है.

क्या आपको इस एपीआई का इस्तेमाल करना है?

क्या आपको अपनी साइट पर File System Access API का इस्तेमाल करना है? आपसे मिली मदद से, हमें सुविधाओं को प्राथमिकता देने में मदद मिलती है. साथ ही, दूसरे ब्राउज़र वेंडर को पता चलता है कि उनकी मदद करना कितना ज़रूरी है.

  • WICG चर्चा थ्रेड पर बताएं कि आपको इसे कैसे इस्तेमाल करना है.
  • हैशटैग #FileSystemAccess का इस्तेमाल करके @ChromiumDev को एक ट्वीट भेजें और हमें बताएं कि उसका इस्तेमाल कहां और कैसे किया जा रहा है.

मददगार लिंक

स्वीकार हैं

File System Access API स्पेसिफ़िकेशन को Mari देश Kruisselbrink ने लिखा था.