File System Access API की मदद से, वेब ऐप्लिकेशन सीधे तौर पर उपयोगकर्ता के डिवाइस पर मौजूद फ़ाइलों और फ़ोल्डर में बदलाव पढ़ सकते हैं या उन्हें सेव कर सकते हैं.
पब्लिश किया गया: 19 अगस्त, 2024
फ़ाइल सिस्टम ऐक्सेस एपीआई की मदद से डेवलपर, ऐसे वेब ऐप्लिकेशन बना सकते हैं जो उपयोगकर्ता के डिवाइस पर मौजूद फ़ाइलों के साथ इंटरैक्ट करते हैं. जैसे, आईडीई, फ़ोटो और वीडियो एडिटर, टेक्स्ट एडिटर वगैरह. जब कोई उपयोगकर्ता किसी वेब ऐप्लिकेशन को ऐक्सेस करने की अनुमति देता है, तब यह एपीआई उसे सीधे तौर पर उपयोगकर्ता के डिवाइस पर मौजूद फ़ाइलों और फ़ोल्डर में बदलाव करने या उन्हें सेव करने की अनुमति देता है. फ़ाइल सिस्टम ऐक्सेस एपीआई, फ़ाइलों को पढ़ने और लिखने के अलावा, डायरेक्ट्री खोलने और उसके कॉन्टेंट की गिनती करने की सुविधा भी देता है.
अगर आपने पहले फ़ाइलों को पढ़ने और लिखने का काम किया है, तो मैं जो जानकारी शेयर करने जा रहा हूं वह आपके लिए जानी-पहचानी होगी. हमारा सुझाव है कि आप इसे पढ़ें, क्योंकि सभी सिस्टम एक जैसे नहीं होते.
File System Access API, Windows, macOS, ChromeOS, Linux, और Android पर ज़्यादातर Chromium ब्राउज़र के साथ काम करता है. हालांकि, Brave ब्राउज़र में यह सुविधा फ़िलहाल सिर्फ़ फ़्लैग के पीछे उपलब्ध है.
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;
});
फ़ाइल को लोकल फ़ाइल सिस्टम में लिखना
टेक्स्ट एडिटर में, किसी फ़ाइल को दो तरीकों से सेव किया जा सकता है: सेव करें और इस रूप में सेव करें. Save फ़ंक्शन, पहले से मिले फ़ाइल हैंडल का इस्तेमाल करके, बदलावों को वापस मूल फ़ाइल में लिखता है. हालांकि, Save As एक नई फ़ाइल बनाता है. इसलिए, इसके लिए एक नए फ़ाइल हैंडल की ज़रूरत होती है.
नई फ़ाइल बनाना
किसी फ़ाइल को सेव करने के लिए, 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() तरीके का इस्तेमाल करके, फ़ाइलें और फ़ोल्डर बनाए या ऐक्सेस किए जा सकते हैं. options ऑब्जेक्ट में create कुंजी और true या false की बूलियन वैल्यू पास करके, यह तय किया जा सकता है कि अगर कोई नई फ़ाइल या फ़ोल्डर मौजूद नहीं है, तो उसे बनाया जाना चाहिए या नहीं.
// 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 ऑब्जेक्ट के साथ एक प्रॉमिस दिखाता है. अगर ड्रैग किया गया आइटम कोई डायरेक्ट्री है, तो यह 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 टीम ने File System Access API को डिज़ाइन और लागू किया है. इसके लिए, Controlling Access to Powerful Web Platform Features में बताए गए मुख्य सिद्धांतों का इस्तेमाल किया गया है. इनमें उपयोगकर्ता का कंट्रोल, पारदर्शिता, और उपयोगकर्ता के लिए आसानी से इस्तेमाल करने की सुविधा शामिल है.
किसी फ़ाइल को खोलना या नई फ़ाइल को सेव करना
फ़ाइल खोलते समय, उपयोगकर्ता फ़ाइल पिकर का इस्तेमाल करके किसी फ़ाइल या डायरेक्ट्री को पढ़ने की अनुमति देता है.
सुरक्षित कॉन्टेक्स्ट से फ़ाइल पिकर को सिर्फ़ तब दिखाया जा सकता है, जब उपयोगकर्ता कोई कार्रवाई करे. अगर उपयोगकर्ता अपना फ़ैसला बदलते हैं, तो वे फ़ाइल पिकर में जाकर चुने गए विकल्प को रद्द कर सकते हैं. इससे साइट को किसी भी चीज़ का ऐक्सेस नहीं मिलता. यह <input type="file"> एलिमेंट के जैसा ही काम करता है.
इसी तरह, जब कोई वेब ऐप्लिकेशन नई फ़ाइल सेव करना चाहता है, तो ब्राउज़र, फ़ाइल सेव करने वाला पिकर दिखाता है. इससे उपयोगकर्ता को नई फ़ाइल का नाम और जगह तय करने की अनुमति मिलती है. उपयोगकर्ता डिवाइस पर एक नई फ़ाइल सेव कर रहा है. वह किसी मौजूदा फ़ाइल को नहीं बदल रहा है. इसलिए, फ़ाइल पिकर ऐप्लिकेशन को फ़ाइल में बदलाव करने की अनुमति देता है.
पाबंदी वाले फ़ोल्डर
उपयोगकर्ताओं और उनके डेटा को सुरक्षित रखने के लिए, ब्राउज़र कुछ फ़ोल्डर में सेव करने की सुविधा को सीमित कर सकता है. उदाहरण के लिए, Windows और macOS Library फ़ोल्डर जैसे मुख्य ऑपरेटिंग सिस्टम फ़ोल्डर. ऐसा होने पर, ब्राउज़र एक प्रॉम्प्ट दिखाता है और उपयोगकर्ता से कोई दूसरा फ़ोल्डर चुनने के लिए कहता है.
किसी मौजूदा फ़ाइल या डायरेक्ट्री में बदलाव करना
वेब ऐप्लिकेशन, उपयोगकर्ता की अनुमति के बिना डिस्क पर मौजूद किसी फ़ाइल में बदलाव नहीं कर सकता.
अनुमति का अनुरोध करने वाला प्रॉम्प्ट
अगर कोई व्यक्ति किसी ऐसी फ़ाइल में बदलाव सेव करना चाहता है जिसे उसने पहले पढ़ने का ऐक्सेस दिया था, तो ब्राउज़र अनुमति का अनुरोध करने वाला प्रॉम्प्ट दिखाता है. इसमें साइट को डिस्क में बदलाव करने की अनुमति देने का अनुरोध किया जाता है. अनुमति का अनुरोध सिर्फ़ उपयोगकर्ता के जेस्चर से ट्रिगर किया जा सकता है. उदाहरण के लिए, 'सेव करें' बटन पर क्लिक करके.
इसके अलावा, कई फ़ाइलों में बदलाव करने वाला वेब ऐप्लिकेशन, जैसे कि आईडीई, फ़ाइल खोलने के समय बदलावों को सेव करने की अनुमति भी मांग सकता है.
अगर उपयोगकर्ता 'रद्द करें' विकल्प चुनता है और लिखने का ऐक्सेस नहीं देता है, तो वेब ऐप्लिकेशन लोकल फ़ाइल में बदलाव सेव नहीं कर सकता. इसमें उपयोगकर्ता को अपना डेटा सेव करने का कोई दूसरा तरीका उपलब्ध कराना चाहिए. उदाहरण के लिए, "फ़ाइल डाउनलोड करें" का विकल्प देकर या डेटा को क्लाउड में सेव करके.
पारदर्शिता
जब कोई उपयोगकर्ता किसी वेब ऐप्लिकेशन को लोकल फ़ाइल सेव करने की अनुमति देता है, तो ब्राउज़र पता बार में एक आइकॉन दिखाता है. इस आइकॉन पर क्लिक करने से, एक पॉप-ओवर खुलता है. इसमें उन फ़ाइलों की सूची दिखती है जिनका ऐक्सेस उपयोगकर्ता ने दिया है. उपयोगकर्ता के पास, उस ऐक्सेस को कभी भी वापस लेने का विकल्प होता है.
अनुमति बनाए रखना
जब तक वेब ऐप्लिकेशन के सभी टैब बंद नहीं हो जाते, तब तक वह फ़ाइल में बदलावों को सेव करता रहेगा. इसके लिए, वह आपसे अनुमति नहीं मांगेगा. टैब बंद होने के बाद, साइट के पास सभी ऐक्सेस नहीं रहते. अगली बार जब उपयोगकर्ता वेब ऐप्लिकेशन का इस्तेमाल करेगा, तब उसे फ़ाइलों को ऐक्सेस करने के लिए फिर से कहा जाएगा.
सुझाव/राय दें या शिकायत करें
हम फ़ाइल सिस्टम ऐक्सेस एपीआई के बारे में आपका अनुभव जानना चाहते हैं.
हमें एपीआई डिज़ाइन के बारे में बताएं
क्या एपीआई के बारे में कुछ ऐसा है जो आपकी उम्मीद के मुताबिक काम नहीं करता? इसके अलावा, क्या आपको अपने आइडिया को लागू करने के लिए, कुछ और तरीकों या प्रॉपर्टी की ज़रूरत है? क्या आपको सुरक्षा मॉडल के बारे में कोई सवाल पूछना है या कोई टिप्पणी करनी है?
- WICG File System Access GitHub repo पर, स्पेसिफ़िकेशन से जुड़ी समस्या की शिकायत करें या किसी मौजूदा समस्या पर अपने विचार जोड़ें.
क्या आपको लागू करने में कोई समस्या आ रही है?
क्या आपको Chrome के साथ काम करने में कोई गड़बड़ी मिली? या क्या लागू करने का तरीका, स्पेसिफ़िकेशन से अलग है?
- https://new.crbug.com पर जाकर, गड़बड़ी की रिपोर्ट करें. रिपोर्ट में ज़्यादा से ज़्यादा जानकारी शामिल करें. साथ ही, गड़बड़ी को दोबारा बनाने के निर्देश दें. इसके अलावा, कॉम्पोनेंट को
Blink>Storage>FileSystemपर सेट करें.
क्या आपको एपीआई का इस्तेमाल करना है?
क्या आपको अपनी साइट पर File System Access API का इस्तेमाल करना है? सार्वजनिक तौर पर आपकी मदद से, हमें सुविधाओं को प्राथमिकता देने में मदद मिलती है. साथ ही, इससे अन्य ब्राउज़र वेंडर को पता चलता है कि इन सुविधाओं को सपोर्ट करना कितना ज़रूरी है.
- WICG Discourse थ्रेड पर, हमें बताएं कि आपको इसका इस्तेमाल कैसे करना है.
- @ChromiumDev को ट्वीट करें. इसके लिए, हैशटैग
#FileSystemAccessका इस्तेमाल करें. साथ ही, हमें बताएं कि इसका इस्तेमाल कहां और कैसे किया जा रहा है.
काम के लिंक
- लोगों को जानकारी देने की सुविधा
- फ़ाइल सिस्टम ऐक्सेस करने की खास जानकारी और फ़ाइल की खास जानकारी
- ट्रैकिंग बग
- ChromeStatus.com एंट्री
- टाइपस्क्रिप्ट की परिभाषाएं
- File System Access API - Chromium Security Model
- Blink कॉम्पोनेंट:
Blink>Storage>FileSystem
Acknowledgements
File System Access API की खास जानकारी Marijn Kruisselbrink ने लिखी थी.