File System Access API की मदद से, वेब ऐप्लिकेशन सीधे तौर पर उपयोगकर्ता के डिवाइस पर मौजूद फ़ाइलों और फ़ोल्डर में बदलावों को पढ़ सकते हैं या सेव कर सकते हैं.
File System Access API क्या है?
फ़ाइल सिस्टम ऐक्सेस एपीआई की मदद से, डेवलपर ऐसे बेहतरीन वेब ऐप्लिकेशन बना सकते हैं जो उपयोगकर्ता के लोकल डिवाइस पर मौजूद फ़ाइलों के साथ इंटरैक्ट करते हैं. जैसे, आईडीई, फ़ोटो और वीडियो एडिटर, टेक्स्ट एडिटर वगैरह. जब कोई उपयोगकर्ता किसी वेब ऐप्लिकेशन को ऐक्सेस देता है, तो यह एपीआई उसे उपयोगकर्ता के डिवाइस पर मौजूद फ़ाइलों और फ़ोल्डर में बदलावों को सीधे पढ़ने या सेव करने की अनुमति देता है. फ़ाइल सिस्टम ऐक्सेस एपीआई, फ़ाइलों को पढ़ने और उनमें बदलाव करने के अलावा, डायरेक्ट्री खोलने और उसके कॉन्टेंट की जानकारी देने की सुविधा भी देता है.
अगर आपने पहले फ़ाइलों को पढ़ने और उनमें बदलाव करने के बारे में काम किया है, तो आपको यहां बताई गई बातों के बारे में पता होगा. हमारा सुझाव है कि आप इसे पढ़ें, क्योंकि सभी सिस्टम एक जैसे नहीं होते.
फ़ाइल सिस्टम ऐक्सेस एपीआई, Windows, macOS, ChromeOS, और Linux पर काम करने वाले ज़्यादातर Chromium ब्राउज़र पर काम करता है. हालांकि, Brave ब्राउज़र में यह सुविधा फ़िलहाल सिर्फ़ फ़्लैग के पीछे उपलब्ध है. Android के लिए, crbug.com/1011535 के संदर्भ में काम किया जा रहा है.
File System Access API का इस्तेमाल करना
फ़ाइल सिस्टम ऐक्सेस एपीआई की सुविधाओं और फ़ायदों को दिखाने के लिए, मैंने एक फ़ाइल टेक्स्ट एडिटर लिखा है. इसकी मदद से, टेक्स्ट फ़ाइल खोली जा सकती है, उसमें बदलाव किया जा सकता है, और बदलावों को डिस्क पर सेव किया जा सकता है. इसके अलावा, नई फ़ाइल बनाई जा सकती है और उसमें किए गए बदलावों को डिस्क पर सेव किया जा सकता है. यह कोई खास सुविधा नहीं है, लेकिन इसमें आपको कॉन्सेप्ट समझने के लिए ज़रूरी जानकारी मिलती है.
ब्राउज़र समर्थन
फ़ीचर का पता लगाना
यह पता करने के लिए कि File System Access API काम करता है या नहीं, देखें कि आपका पसंदीदा पिकर तरीका मौजूद है या नहीं.
if ('showOpenFilePicker' in self) {
// The `showOpenFilePicker()` method of the File System Access API is supported.
}
इसे आज़माएं
टेक्स्ट एडिटर के डेमो में, 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;
});
फ़ाइल को लोकल फ़ाइल सिस्टम में लिखना
टेक्स्ट एडिटर में, फ़ाइल को सेव करने के दो तरीके हैं: सेव करें और इस रूप में सेव करें. सेव करें, पहले से हासिल किए गए फ़ाइल हैंडल का इस्तेमाल करके, बदलावों को ओरिजनल फ़ाइल में वापस लिखता है. हालांकि, इसके तौर पर सेव करें से नई फ़ाइल बनती है. इसलिए, इसके लिए नए फ़ाइल हैंडल की ज़रूरत होती है.
नई फ़ाइल बनाना
किसी फ़ाइल को सेव करने के लिए, 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
को डिफ़ॉल्ट फ़ाइल नाम के तौर पर सुझाना चाहे. showSaveFilePicker
विकल्पों के हिस्से के तौर पर suggestedName
प्रॉपर्टी पास करके, ऐसा किया जा सकता है.
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' }
को मेथड में पास करें.
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()
का इस्तेमाल करके सभी फ़ाइलों को एक साथ प्रोसेस करें.
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 });
किसी फ़ाइल या फ़ोल्डर को सीधे मिटाना
अगर आपके पास किसी फ़ाइल या डायरेक्ट्री हैंडल का ऐक्सेस है, तो उसे हटाने के लिए, FileSystemFileHandle
या
FileSystemDirectoryHandle
पर remove()
को कॉल करें.
// 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
ऑब्जेक्ट के साथ एक प्रॉमिस दिखाता है. वहीं, अगर खींचे गए आइटम की कैटगरी डायरेक्ट्री है, तो DataTransferItem.getAsFileSystemHandle()
तरीका, FileSystemDirectoryHandle
ऑब्जेक्ट के साथ एक प्रॉमिस दिखाता है. नीचे दी गई लिस्टिंग में, इस सुविधा के काम करने का तरीका बताया गया है. ध्यान दें कि खींचकर छोड़ने वाले इंटरफ़ेस का DataTransferItem.kind
, फ़ाइलों और डायरेक्ट्री, दोनों के लिए "file"
है. वहीं, File System Access API का 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 });
ऑरिजिनल निजी फ़ाइल सिस्टम से, परफ़ॉर्मेंस के लिए ऑप्टिमाइज़ की गई फ़ाइलें ऐक्सेस करना
ऑरिजिन का निजी फ़ाइल सिस्टम, एक खास तरह की फ़ाइल का ऐक्सेस देता है. यह फ़ाइल, परफ़ॉर्मेंस के लिए काफ़ी ऑप्टिमाइज़ की गई होती है. उदाहरण के लिए, फ़ाइल के कॉन्टेंट में बदलाव करने के लिए, फ़ाइल में मौजूदा जगह पर बदलाव करने का ऐक्सेस और खास ऐक्सेस दिया जाता है. 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>
एलिमेंट की मदद से एमुलेट किया जा सकता है.
हमने browser-fs-access नाम की एक लाइब्रेरी डेवलप की है. यह लाइब्रेरी जहां भी हो सके वहां File System Access API का इस्तेमाल करती है. साथ ही, अन्य सभी मामलों में इन सबसे अच्छे विकल्पों का इस्तेमाल करती है.
सुरक्षा और अनुमतियां
Chrome की टीम ने वेब प्लैटफ़ॉर्म की बेहतर सुविधाओं के ऐक्सेस को कंट्रोल करना में बताए गए मुख्य सिद्धांतों का इस्तेमाल करके, फ़ाइल सिस्टम ऐक्सेस एपीआई को डिज़ाइन और लागू किया है. इन सिद्धांतों में, उपयोगकर्ता कंट्रोल और पारदर्शिता के साथ-साथ, उपयोगकर्ता के लिए सुविधाओं को आसान बनाने के बारे में बताया गया है.
कोई फ़ाइल खोलना या नई फ़ाइल सेव करना
फ़ाइल खोलने पर, उपयोगकर्ता फ़ाइल पिकर का इस्तेमाल करके, फ़ाइल या डायरेक्ट्री को पढ़ने की अनुमति देता है.
ओपन फ़ाइल पिकर को सिर्फ़ उपयोगकर्ता के जेस्चर का इस्तेमाल करके तब दिखाया जा सकता है, जब उसे सुरक्षित कॉन्टेक्स्ट से दिखाया जा रहा हो. अगर उपयोगकर्ताओं का इरादा बदल जाता है, तो वे फ़ाइल चुनने वाले टूल में जाकर, चुने गए विकल्प को रद्द कर सकते हैं. ऐसा करने पर, साइट को किसी भी फ़ाइल का ऐक्सेस नहीं मिलता. यह व्यवहार, <input type="file">
एलिमेंट के व्यवहार जैसा ही है.
इसी तरह, जब कोई वेब ऐप्लिकेशन कोई नई फ़ाइल सेव करना चाहता है, तो ब्राउज़र 'फ़ाइल सेव करें' पिकर दिखाता है. इससे उपयोगकर्ता को नई फ़ाइल का नाम और जगह तय करने में मदद मिलती है. उपयोगकर्ता, डिवाइस पर कोई नई फ़ाइल सेव कर रहे हैं, न कि किसी मौजूदा फ़ाइल को ओवरराइट कर रहे हैं. इसलिए, फ़ाइल पिकर ऐप्लिकेशन को फ़ाइल में बदलाव करने की अनुमति देता है.
पाबंदी वाले फ़ोल्डर
उपयोगकर्ताओं और उनके डेटा को सुरक्षित रखने के लिए, ब्राउज़र कुछ फ़ोल्डर में सेव करने की सुविधा पर पाबंदी लगा सकता है. जैसे, Windows, macOS लाइब्रेरी फ़ोल्डर जैसे मुख्य ऑपरेटिंग सिस्टम फ़ोल्डर. ऐसा होने पर, ब्राउज़र एक प्रॉम्प्ट दिखाता है और उपयोगकर्ता से कोई दूसरा फ़ोल्डर चुनने के लिए कहता है.
किसी मौजूदा फ़ाइल या डायरेक्ट्री में बदलाव करना
कोई वेब ऐप्लिकेशन, उपयोगकर्ता की अनुमति लिए बिना डिस्क पर मौजूद किसी फ़ाइल में बदलाव नहीं कर सकता.
अनुमति का अनुरोध
अगर कोई व्यक्ति किसी ऐसी फ़ाइल में बदलाव करना चाहता है जिसका उसने पहले पढ़ने का ऐक्सेस दिया था, तो ब्राउज़र एक अनुमति वाला प्रॉम्प्ट दिखाता है. इसमें, साइट से डिस्क पर बदलावों को सेव करने की अनुमति मांगी जाती है. अनुमति का अनुरोध, सिर्फ़ उपयोगकर्ता के जेस्चर से ट्रिगर किया जा सकता है. उदाहरण के लिए, सेव करें बटन पर क्लिक करके.
इसके अलावा, एक से ज़्यादा फ़ाइलों में बदलाव करने वाला वेब ऐप्लिकेशन, फ़ाइल खोलने के समय बदलावों को सेव करने की अनुमति भी मांग सकता है. जैसे, आईडीई.
अगर उपयोगकर्ता 'रद्द करें' चुनता है और लिखने का ऐक्सेस नहीं देता है, तो वेब ऐप्लिकेशन, लोकल फ़ाइल में किए गए बदलावों को सेव नहीं कर सकता. इसमें उपयोगकर्ता को अपना डेटा सेव करने का कोई दूसरा तरीका उपलब्ध कराना चाहिए. उदाहरण के लिए, फ़ाइल को"डाउनलोड" करने या क्लाउड में डेटा सेव करने का तरीका.
पारदर्शिता
जब कोई उपयोगकर्ता किसी वेब ऐप्लिकेशन को लोकल फ़ाइल सेव करने की अनुमति देता है, तो ब्राउज़र, पता बार में एक आइकॉन दिखाता है. आइकॉन पर क्लिक करने से एक पॉप-ओवर खुलता है. इसमें उन फ़ाइलों की सूची दिखती है जिनका ऐक्सेस उपयोगकर्ता ने दिया है. उपयोगकर्ता चाहे, तो इस ऐक्सेस को कभी भी वापस ले सकता है.
अनुमति का बना रहना
जब तक फ़ाइल के ऑरिजिन के सभी टैब बंद नहीं किए जाते, तब तक वेब ऐप्लिकेशन, आपसे पूछे बिना फ़ाइल में किए गए बदलावों को सेव करता रहेगा. टैब बंद होने के बाद, साइट का ऐक्सेस हट जाता है. अगली बार जब उपयोगकर्ता वेब ऐप्लिकेशन का इस्तेमाल करेगा, तो उसे फ़ाइलों का ऐक्सेस पाने के लिए फिर से कहा जाएगा.
सुझाव/राय दें या शिकायत करें
हम File System Access API के इस्तेमाल के आपके अनुभवों के बारे में जानना चाहते हैं.
हमें एपीआई के डिज़ाइन के बारे में बताएं
क्या एपीआई में कुछ ऐसा है जो आपकी उम्मीद के मुताबिक काम नहीं करता? क्या आपके आइडिया को लागू करने के लिए, कोई तरीका या प्रॉपर्टी मौजूद नहीं है? क्या आपका सुरक्षा मॉडल के बारे में कोई सवाल या टिप्पणी है?
- WICG फ़ाइल सिस्टम ऐक्सेस GitHub repo पर, खास जानकारी से जुड़ी समस्या दर्ज करें या किसी मौजूदा समस्या के बारे में अपनी राय दें.
क्या लागू करने में समस्या आ रही है?
क्या आपको Chrome में इस सुविधा को लागू करने में कोई गड़बड़ी मिली? या क्या इसे लागू करने का तरीका, खास जानकारी से अलग है?
- https://new.crbug.com पर जाकर, गड़बड़ी की शिकायत करें. इसमें ज़्यादा से ज़्यादा जानकारी शामिल करें. साथ ही, गड़बड़ी को दोहराने के लिए निर्देश दें और कॉम्पोनेंट को
Blink>Storage>FileSystem
पर सेट करें. Glitch, तुरंत समस्या की जानकारी शेयर करने के लिए बहुत अच्छा है.
क्या आपको एपीआई का इस्तेमाल करना है?
क्या आपको अपनी साइट पर File System Access API का इस्तेमाल करना है? सार्वजनिक तौर पर सहायता पाने से, हमें सुविधाओं को प्राथमिकता देने में मदद मिलती है. साथ ही, इससे अन्य ब्राउज़र वेंडर को यह पता चलता है कि इन सुविधाओं को उपलब्ध कराना कितना ज़रूरी है.
- WICG के Discourse थ्रेड पर शेयर करें कि आपको इसका इस्तेमाल कैसे करना है.
#FileSystemAccess
हैशटैग का इस्तेमाल करके, @ChromiumDev को ट्वीट करें और हमें बताएं कि इसका इस्तेमाल कहां और कैसे किया जा रहा है.
मदद के लिए लिंक
- सार्वजनिक तौर पर जानकारी देने की सुविधा
- फ़ाइल सिस्टम ऐक्सेस स्पेसिफ़िकेशन और फ़ाइल स्पेसिफ़िकेशन
- बग को ट्रैक करना
- ChromeStatus.com पर मौजूद जानकारी
- TypeScript की परिभाषाएं
- फ़ाइल सिस्टम को ऐक्सेस करने का एपीआई - Chromium का सिक्योरिटी मॉडल
- Blink कॉम्पोनेंट:
Blink>Storage>FileSystem
आभार
फ़ाइल सिस्टम को ऐक्सेस करने वाले एपीआई के स्पेसिफ़िकेशन को Marijn Kruisselbrink ने लिखा है.