يقدّم معيار نظام الملفات نظام ملفات خاصًا بالمصدر (OPFS) كنقطة نهاية تخزين خاصة بمصدر الصفحة ولا تظهر للمستخدم، وهي توفّر إمكانية وصول اختيارية إلى نوع خاص من الملفات المحسّنة للغاية لتحقيق الأداء الأفضل.
دعم المتصفح
يتيح نظام الملفات الخاص الأصلي للمتصفّحات الحديثة إمكانية الوصول إلى الملفات، وقد تمّ توحيده من قِبل مجموعة عمل تكنولوجيا تطبيقات النص الفائق على الويب (WHATWG) في معيار نظام الملفات.
الحافز
عندما تفكر في الملفات على جهاز الكمبيوتر، ربما تفكر في التسلسل الهرمي للملفات: الملفات المنظَّمة في مجلدات يمكنك استكشافها باستخدام مستكشف الملفات في نظام التشغيل. على سبيل المثال، في نظام التشغيل Windows، قد تكون قائمة "المهام" للمستخدم "توفيق" في C:\Users\Tom\Documents\ToDo.txt
. في هذا المثال، ToDo.txt
هو اسم الملف، وUsers
وTom
وDocuments
هي أسماء المجلدات. يمثّل الحرف C: على نظام التشغيل Windows الدليل الجذري لمحرك الأقراص.
الطريقة التقليدية للعمل مع الملفات على الويب
لتعديل قائمة "المهام التي يجب إكمالها" في أحد تطبيقات الويب، اتّبِع الخطوات التالية:
- يحمّل المستخدم الملف إلى خادم أو يفتحه على العميل باستخدام
<input type="file">
. - يُجري المستخدم التغييرات، ثم ينزّل الملف الناتج الذي يحتوي على
<a download="ToDo.txt>
تم إدخالهclick()
آليًا من خلال JavaScript. - لفتح المجلدات، يمكنك استخدام سمة خاصة في
<input type="file" webkitdirectory>
، والتي تتيح استخدامها في جميع المتصفّحات تقريبًا على الرغم من اسمها الحصري.
طريقة حديثة للعمل مع الملفات على الويب
لا يمثّل هذا المسار طريقة المستخدمين في تعديل الملفات، ويعني ذلك أنّ المستخدمين يحصلون في النهاية على نُسخ تم تنزيلها من ملفات الإدخال. لذلك، قدّمت File System Access API ثلاث طرق لاختيار الملفات، وهي showOpenFilePicker()
وshowSaveFilePicker()
وshowDirectoryPicker()
، وتعمل هذه الطرق على النحو الذي يشير إليه اسمها. وتتيح هذه الميزة عملية الدفع على النحو التالي:
- افتح
ToDo.txt
باستخدامshowOpenFilePicker()
، واحصل على عنصرFileSystemFileHandle
. - من عنصر
FileSystemFileHandle
، احصل علىFile
من خلال استدعاء طريقةgetFile()
الخاصة بملف المعالجة. - عدِّل الملف، ثم اتصل على
requestPermission({mode: 'readwrite'})
باستخدام الاسم المعرِّف. - إذا وافق المستخدم على طلب الإذن، احفظ التغييرات مرة أخرى في الملف الأصلي.
- بدلاً من ذلك، يمكنك الاتصال بالرقم
showSaveFilePicker()
والسماح للمستخدم باختيار ملف جديد. (إذا اختار المستخدم ملفًا سبق فتحه، سيتم استبدال محتوياته). بالنسبة إلى عمليات الحفظ المتكررة، يمكنك الاحتفاظ باسم معرِّف الملف، حتى لا تضطر إلى عرض مربّع حوار حفظ الملف مرة أخرى.
قيود العمل مع الملفات على الويب
إنّ الملفات والمجلدات التي يمكن الوصول إليها من خلال هذه الطرق تكون في ما يمكن تسميته بنظام الملفات المرئي للمستخدم. يتم وضع علامة الويب على الملفات المحفوظة من الويب، والملفات القابلة للتنفيذ على وجه التحديد، وذلك لعرض تحذير إضافي يمكن أن يعرضه نظام التشغيل قبل تنفيذ ملف يُحتمل أن يكون خطيرًا. كميزة أمان إضافية، يتم أيضًا حماية الملفات التي يتم الحصول عليها من الويب من خلال ميزة التصفّح الآمن، والتي يمكنك اعتبارها، من أجل التبسيط وفي سياق هذه المقالة، عملية فحص الفيروسات المستندة إلى السحابة الإلكترونية. عند كتابة البيانات في ملف باستخدام واجهة برمجة التطبيقات File System Access API، لا تتم الكتابة في الملف نفسه، بل يتم استخدام ملف مؤقت. ولا يتم تعديل الملف نفسه إلا إذا اجتاز جميع عمليات فحص الأمان هذه. كما يمكنك أن تتخيل، يؤدي هذا العمل إلى إبطاء عمليات الملفات نسبيًا، على الرغم من التحسينات التي تم تطبيقها كلما أمكن ذلك، على سبيل المثال، على نظام التشغيل macOS. ومع ذلك، فإنّ كلّ طلب write()
مستقل بذاته، لذا يتمّ فتح الملف واختيار الموضع المحدّد وكتابة البيانات في النهاية.
الملفات كأساس للمعالجة
وفي الوقت نفسه، تشكّل الملفات طريقة ممتازة لتسجيل البيانات. على سبيل المثال، تخزّن SQLite قواعد بيانات كاملة في ملف واحد. ومن الأمثلة الأخرى الخرائط المنخفضة الدقة المستخدَمة في معالجة الصور. خرائط Mipmap هي تسلسلات محسَّنة من الصور يتم احتسابها مسبقًا، وكل منها يمثّل درجة أقل تدريجيًا من الدقة مقارنةً بالصورة السابقة، ما يجعل العديد من العمليات أسرع، مثل التصغير أو التكبير. كيف يمكن لتطبيقات الويب الاستفادة من مزايا الملفات بدون تكاليف الأداء المرتبطة بمعالجة الملفات المستندة إلى الويب؟ الإجابة هي نظام الملفات الخاص الأصلي.
نظام الملفات الخاص بالمستخدم مقارنةً بنظام الملفات الخاص بالمصدر
على عكس نظام الملفات الظاهر للمستخدم والذي يتم تصفحه باستخدام مستكشف الملفات في نظام التشغيل، لا يمكن للمستخدمين الاطّلاع على نظام الملفات الخاص الأصلي، والذي يتضمّن ملفات ومجلدات يمكنك قراءتها وكتابتها ونقلها وإعادة تسميتها. الملفات والمجلدات في نظام الملفات الخاص بالمصدر، كما يوحي الاسم، تكون خاصة، وبشكل أكثر تحديدًا، تكون خاصة بمصدر الموقع الإلكتروني. يمكنك معرفة مصدر صفحة معيّنة عن طريق كتابة location.origin
في وحدة تحكّم أدوات مطوّري البرامج. على سبيل المثال، مصدر الصفحة https://developer.chrome.com/articles/
هو https://developer.chrome.com
(أي أنّ الجزء /articles
ليس جزءًا من المصدر). يمكنك الاطّلاع على مزيد من المعلومات عن نظرية الأصول في مقالة فهم "الموقع الإلكتروني نفسه" و "المصدر نفسه". يمكن لجميع الصفحات التي تشترك في المصدر نفسه الاطّلاع على بيانات نظام الملفات الخاص بالمستخدم نفسه، وبالتالي يمكن لـ "https://developer.chrome.com/docs/extensions/mv3/getstarted/extensions-101/
" الاطّلاع على التفاصيل نفسها الواردة في المثال السابق. لكل مصدر نظام ملفات خاص مستقل، ما يعني أنّ نظام الملفات الخاص لمصدر https://developer.chrome.com
يختلف تمامًا عن نظام الملفات الخاص لمصدر https://web.dev
مثلاً. في نظام التشغيل Windows، يكون الدليل الجذر لنظام الملفات المرئي للمستخدم هو C:\\
.
يتمثل العنصر المكافئ لنظام الملفات الخاص بالمصدر في دليل جذر فارغ في البداية لكل مصدر يتم الوصول إليه من خلال استدعاء الطريقة غير المتزامنة
navigator.storage.getDirectory()
.
للاطّلاع على مقارنة بين نظام الملفات المرئي للمستخدم ونظام الملفات الخاص الأصلي، اطّلِع على المخطّط البياني التالي. يوضّح المخطّط البياني أنّه باستثناء الدليل الجذر، كل شيء آخر متطابق من الناحية المفاهيمية، مع تسلسل هرمي للملفات والمجلدات لتنظيمها وترتيبها حسب الحاجة لتلبية احتياجات البيانات ومساحة التخزين.
تفاصيل نظام الملفات الخاص الأصلي
تمامًا مثل آليات التخزين الأخرى في المتصفّح (مثل localStorage أو IndexedDB)، يخضع نظام الملفات الخاص الأصلي لقيود مساحة التخزين المتوفّرة في المتصفّح. عندما يُجري المستخدم عملية محو جميع بيانات التصفّح أو جميع بيانات المواقع الإلكترونية، سيتم أيضًا حذف نظام الملفات الخاص الأصلي. يمكنك استدعاء navigator.storage.estimate()
والاطّلاع على إدخال usage
في عنصر الاستجابة الناتج لمعرفة مقدار مساحة التخزين التي يستهلكها تطبيقك حاليًا، والتي يتم تقسيمها حسب آلية التخزين في عنصر usageDetails
، حيث تريد الاطّلاع على إدخال fileSystem
على وجه التحديد. بما أنّ نظام الملفات الخاص الأصلي غير مرئي للمستخدم، لا تظهر أي طلبات للحصول على الأذونات ولا يتم إجراء أي عمليات تحقّق من ميزة "التصفّح الآمن".
الحصول على إذن الوصول إلى الدليل الجذري
للوصول إلى الدليل الجذر، نفِّذ الأمر التالي. سينتهي بك الأمر باسم دليل فارغ، وبشكل أكثر تحديدًا، FileSystemDirectoryHandle
.
const opfsRoot = await navigator.storage.getDirectory();
// A FileSystemDirectoryHandle whose type is "directory"
// and whose name is "".
console.log(opfsRoot);
سلسلة التعليمات الرئيسية أو Web Worker
هناك طريقتان لاستخدام نظام الملفات الخاص بالمصدر: في الخيط الرئيسي أو في Web Worker. لا يمكن لخيوط Web Worker حظر سلسلة التعليمات الرئيسية، ما يعني في هذا السياق أنّ واجهات برمجة التطبيقات يمكن أن تكون متزامنة، وهو نمط غير مسموح به بشكل عام في سلسلة التعليمات الرئيسية. يمكن أن تكون واجهات برمجة التطبيقات المتزامنة أسرع لأنّها تتجنّب التعامل مع الوعود، وتكون عمليات الملفات عادةً متزامنة بلغات مثل C التي يمكن تجميعها إلى WebAssembly.
// This is synchronous C code.
FILE *f;
f = fopen("example.txt", "w+");
fputs("Some text\n", f);
fclose(f);
إذا كنت بحاجة إلى أسرع عمليات ممكنة على الملفات، أو كنت تتعامل مع WebAssembly، انتقِل إلى استخدام نظام الملفات الخاص بالمصدر في Web Worker. بخلاف ذلك، يمكنك المتابعة.
استخدام نظام الملفات الخاص الأصلي في سلسلة التعليمات الرئيسية
إنشاء ملفات ومجلدات جديدة
بعد إنشاء مجلد جذر، أنشئ ملفات ومجلدات باستخدام الطريقتَين getFileHandle()
وgetDirectoryHandle()
على التوالي. عند ضبط القيمة {create: true}
، سيتم إنشاء الملف أو المجلد إذا لم يكنا متوفّرَين. يمكنك إنشاء تسلسل هرمي للملفات من خلال استدعاء هذه الدوال باستخدام دليل تم إنشاؤه حديثًا كنقطة بداية.
const fileHandle = await opfsRoot
.getFileHandle('my first file', {create: true});
const directoryHandle = await opfsRoot
.getDirectoryHandle('my first folder', {create: true});
const nestedFileHandle = await directoryHandle
.getFileHandle('my first nested file', {create: true});
const nestedDirectoryHandle = await directoryHandle
.getDirectoryHandle('my first nested folder', {create: true});
الوصول إلى الملفات والمجلدات الحالية
إذا كنت تعرف اسمها، يمكنك الوصول إلى الملفات والمجلدات التي تم إنشاؤها سابقًا من خلال استدعاء الطريقتَين getFileHandle()
أو getDirectoryHandle()
مع إدخال اسم الملف أو المجلد.
const existingFileHandle = await opfsRoot.getFileHandle('my first file');
const existingDirectoryHandle = await opfsRoot
.getDirectoryHandle('my first folder');
الحصول على الملف المرتبط بوحدة تحكّم في الملفات للقراءة
يمثّل FileSystemFileHandle
ملفًا في نظام الملفات. للحصول على File
المرتبط، استخدِم طريقة getFile()
. عنصر File
هو نوع معيّن من Blob
، ويمكن استخدامه في أي سياق يمكن فيه استخدام Blob
. على وجه الخصوص، تقبل FileReader
وURL.createObjectURL()
وcreateImageBitmap()
وXMLHttpRequest.send()
كلاً من Blobs
وFiles
. بعبارة أخرى، يؤدي الحصول على File
من FileSystemFileHandle
إلى "إخلاء" البيانات، ما يتيح لك الوصول إليها وإتاحتها لنظام الملفات المرئي للمستخدم.
const file = await fileHandle.getFile();
console.log(await file.text());
الكتابة في ملف من خلال البث
يمكنك بث البيانات إلى ملف من خلال استدعاء createWritable()
الذي ينشئ FileSystemWritableFileStream
يمكنك بعد ذلك write()
المحتوى. في النهاية، عليك close()
البث.
const contents = 'Some text';
// Get a writable stream.
const writable = await fileHandle.createWritable();
// Write the contents of the file to the stream.
await writable.write(contents);
// Close the stream, which persists the contents.
await writable.close();
حذف الملفات والمجلدات
يمكنك حذف الملفات والمجلدات من خلال استدعاء طريقة remove()
المحددة لملف أو دليل معيّن. لحذف مجلد مع جميع المجلدات الفرعية، مرِّر الخيار {recursive: true}
.
await fileHandle.remove();
await directoryHandle.remove({recursive: true});
كخيار بديل، إذا كنت تعرف اسم الملف أو المجلد المطلوب حذفه في دليل، استخدِم طريقة removeEntry()
.
directoryHandle.removeEntry('my first nested file');
نقل الملفات والمجلدات وإعادة تسميتها
يمكنك إعادة تسمية الملفات والمجلدات ونقلها باستخدام الطريقة move()
. يمكن نقل العناصر وإعادة تسميتها معًا أو بشكل منفصل.
// Rename a file.
await fileHandle.move('my first renamed file');
// Move a file to another directory.
await fileHandle.move(nestedDirectoryHandle);
// Move a file to another directory and rename it.
await fileHandle
.move(nestedDirectoryHandle, 'my first renamed and now nested file');
حلّ مسار ملف أو مجلد
لمعرفة مكان ملف أو مجلد معيّن بالنسبة إلى دليل مرجعي، استخدِم الطريقة resolve()
مع تمرير FileSystemHandle
كوسيطة. للحصول على المسار الكامل لملف أو مجلد في نظام الملفات الخاص الأصلي، استخدِم الدليل الجذر كدليل مرجعي تم الحصول عليه من خلال navigator.storage.getDirectory()
.
const relativePath = await opfsRoot.resolve(nestedDirectoryHandle);
// `relativePath` is `['my first folder', 'my first nested folder']`.
التحقّق مما إذا كان اسمان لملف أو مجلد يشيرَان إلى الملف أو المجلد نفسه
في بعض الأحيان، يكون لديك اسمان معرِّفان ولا تعرف ما إذا كانا يشيرَين إلى الملف أو المجلد نفسه. للتحقّق من ذلك، استخدِم طريقة isSameEntry()
.
fileHandle.isSameEntry(nestedFileHandle);
// Returns `false`.
إدراج محتوى مجلد
FileSystemDirectoryHandle
هو مُكرِّر غير متزامن يمكنك تكراره باستخدام حلقة for await…of
. وبصفتها أداة تكرار غير متزامنة، تتيح هذه الطريقة أيضًا استخدام طرق entries()
وvalues()
وkeys()
، ويمكنك الاختيار من بينها حسب المعلومات التي تحتاجها:
for await (let [name, handle] of directoryHandle) {}
for await (let [name, handle] of directoryHandle.entries()) {}
for await (let handle of directoryHandle.values()) {}
for await (let name of directoryHandle.keys()) {}
إدراج محتوى مجلد وكل المجلدات الفرعية بشكل متكرر
من السهل ارتكاب أخطاء عند التعامل مع الحلقات والدوال غير المتزامنة مع التكرار. يمكن أن تُستخدَم الدالة أدناه كنقطة بداية لعرض محتويات مجلد وكل المجلدات الفرعية له، بما في ذلك جميع الملفات وأحجامها. يمكنك تبسيط الدالة إذا لم تكن بحاجة إلى أحجام الملفات، حيث يظهر directoryEntryPromises.push
، وليس handle.getFile()
، ولكن handle
مباشرةً.
const getDirectoryEntriesRecursive = async (
directoryHandle,
relativePath = '.',
) => {
const fileHandles = [];
const directoryHandles = [];
const entries = {};
// Get an iterator of the files and folders in the directory.
const directoryIterator = directoryHandle.values();
const directoryEntryPromises = [];
for await (const handle of directoryIterator) {
const nestedPath = `${relativePath}/${handle.name}`;
if (handle.kind === 'file') {
fileHandles.push({ handle, nestedPath });
directoryEntryPromises.push(
handle.getFile().then((file) => {
return {
name: handle.name,
kind: handle.kind,
size: file.size,
type: file.type,
lastModified: file.lastModified,
relativePath: nestedPath,
handle
};
}),
);
} else if (handle.kind === 'directory') {
directoryHandles.push({ handle, nestedPath });
directoryEntryPromises.push(
(async () => {
return {
name: handle.name,
kind: handle.kind,
relativePath: nestedPath,
entries:
await getDirectoryEntriesRecursive(handle, nestedPath),
handle,
};
})(),
);
}
}
const directoryEntries = await Promise.all(directoryEntryPromises);
directoryEntries.forEach((directoryEntry) => {
entries[directoryEntry.name] = directoryEntry;
});
return entries;
};
استخدام نظام الملفات الخاص بالتطبيق الأصلي في Web Worker
كما هو موضّح سابقًا، لا يمكن لخيوط Web Worker حظر سلسلة المهام الرئيسية، ولهذا السبب يُسمح باستخدام الطرق المتزامنة في هذا السياق.
الحصول على معرّف وصول متزامن
نقطة الدخول إلى أسرع عمليات ممكنة على الملفات هي FileSystemSyncAccessHandle
، ويتم الحصول عليها من FileSystemFileHandle
العادي من خلال استدعاء createSyncAccessHandle()
.
const fileHandle = await opfsRoot
.getFileHandle('my highspeed file.txt', {create: true});
const syncAccessHandle = await fileHandle.createSyncAccessHandle();
طرق الملفات المتزامنة في مكانها
بعد الحصول على معرّف وصول متزامن، يمكنك الوصول إلى طرق الملفات السريعة التي تتم بشكل متزامن.
-
getSize()
: عرض حجم الملف بالبايت -
write()
: تُسجِّل محتوى المخزن المؤقت في الملف، اختياريًا عند إزاحة معيّنة، وتُعرِض عدد البايتات المكتوبة. يتيح التحقّق من العدد المعروض من وحدات البايت التي تمّ كتابتها للمتصلين رصد الأخطاء والعمليات غير المكتملة للكتابة ومعالجتها. read()
: لقراءة محتوى الملف في مخزن مؤقت، اختياريًا عند إزاحة معيّنةtruncate()
: تغيير حجم الملف إلى الحجم المحدَّد-
flush()
: يضمن أنّ محتوى الملف يحتوي على جميع التعديلات التي تم إجراؤها من خلالwrite()
. -
close()
: لإغلاق معرّف الوصول
في ما يلي مثال يستخدم جميع الطرق المذكورة أعلاه.
const opfsRoot = await navigator.storage.getDirectory();
const fileHandle = await opfsRoot.getFileHandle('fast', {create: true});
const accessHandle = await fileHandle.createSyncAccessHandle();
const textEncoder = new TextEncoder();
const textDecoder = new TextDecoder();
// Initialize this variable for the size of the file.
let size;
// The current size of the file, initially `0`.
size = accessHandle.getSize();
// Encode content to write to the file.
const content = textEncoder.encode('Some text');
// Write the content at the beginning of the file.
accessHandle.write(content, {at: size});
// Flush the changes.
accessHandle.flush();
// The current size of the file, now `9` (the length of "Some text").
size = accessHandle.getSize();
// Encode more content to write to the file.
const moreContent = textEncoder.encode('More content');
// Write the content at the end of the file.
accessHandle.write(moreContent, {at: size});
// Flush the changes.
accessHandle.flush();
// The current size of the file, now `21` (the length of
// "Some textMore content").
size = accessHandle.getSize();
// Prepare a data view of the length of the file.
const dataView = new DataView(new ArrayBuffer(size));
// Read the entire file into the data view.
accessHandle.read(dataView);
// Logs `"Some textMore content"`.
console.log(textDecoder.decode(dataView));
// Read starting at offset 9 into the data view.
accessHandle.read(dataView, {at: 9});
// Logs `"More content"`.
console.log(textDecoder.decode(dataView));
// Truncate the file after 4 bytes.
accessHandle.truncate(4);
نسخ ملف من نظام الملفات الخاص الأصلي إلى نظام الملفات الظاهر للمستخدم
كما ذكرنا أعلاه، لا يمكن نقل الملفات من نظام الملفات الخاص الأصلي إلى نظام الملفات الظاهر للمستخدم، ولكن يمكنك نسخ الملفات. بما أنّ showSaveFilePicker()
لا يظهر إلا في سلسلة التعليمات الرئيسية، وليس في سلسلة Worker، احرص على تشغيل الرمز هناك.
// On the main thread, not in the Worker. This assumes
// `fileHandle` is the `FileSystemFileHandle` you obtained
// the `FileSystemSyncAccessHandle` from in the Worker
// thread. Be sure to close the file in the Worker thread first.
const fileHandle = await opfsRoot.getFileHandle('fast');
try {
// Obtain a file handle to a new file in the user-visible file system
// with the same name as the file in the origin private file system.
const saveHandle = await showSaveFilePicker({
suggestedName: fileHandle.name || ''
});
const writable = await saveHandle.createWritable();
await writable.write(await fileHandle.getFile());
await writable.close();
} catch (err) {
console.error(err.name, err.message);
}
تصحيح أخطاء نظام الملفات الخاص الأصلي
إلى أن تتم إضافة أدوات مطوري البرامج المدمجة (راجِع crbug/1284595)، استخدِم إضافة مستكشف نظام الملفات الخاص (OPFS) في Chrome لتصحيح أخطاء نظام الملفات الخاص الأصلي. تم الحصول على لقطة الشاشة أعلاه من قسم إنشاء ملفات ومجلدات جديدة مباشرةً من الإضافة.
بعد تثبيت الإضافة، افتح "أدوات مطوّري البرامج في Chrome"، واختَر علامة التبويب مستكشف نظام الملفات المفتوح (OPFS)، وسيكون بإمكانك بعد ذلك فحص التسلسل الهرمي للملفات. يمكنك حفظ الملفات من نظام الملفات الخاص الأصلي في نظام الملفات الظاهر للمستخدم من خلال النقر على اسم الملف وحذف الملفات والمجلدات من خلال النقر على رمز سلة المهملات.
عرض توضيحي
يمكنك الاطّلاع على نظام الملفات الخاص الأصلي أثناء استخدامه (في حال تثبيت إضافة OPFS Explorer) في عرض توضيحي يستخدمه كخلفية لقاعدة بيانات SQLite تم تجميعها باستخدام WebAssembly. احرص على الاطّلاع على رمز المصدر على Glitch. يُرجى ملاحظة أنّ الإصدار المضمّن أدناه لا يستخدم الخلفية الخاصة بنظام الملفات الخاص بالمصدر (لأنّ عنصر iframe متعدد المصادر)، ولكنّه يستخدمها عند فتح العرض الترويجي في علامة تبويب منفصلة.
الاستنتاجات
لقد حدّد معيار WHATWG نظام الملفات الخاص الأصلي، ما ساهم في تحديد طريقة استخدامنا للملفات والتفاعل معها على الويب. وقد سمح هذا النظام بحالات استخدام جديدة كان من المستحيل تحقيقها باستخدام نظام الملفات المرئي للمستخدم. وقد انضمّ جميع مورّدي المتصفّحات الرئيسيين، وهم Apple وMozilla وGoogle، إلى هذه المبادرة ويتشاركون رؤيتها المشتركة. يعتمد تطوير نظام الملفات الخاص الأصلي على جهود تعاونية، وتعد الملاحظات الواردة من المطوّرين والمستخدمين ضرورية لتطويره. بينما نواصل تحسين المعيار، نرحّب بملاحظاتك حول مستودع whatwg/fs في شكل مشاكل أو طلبات سحب.
روابط ذات صلة
- مواصفات File System Standard
- مستودع File System Standard
- مشاركة WebKit حول File System API مع Origin Private File System
- إضافة OPFS Explorer
الشكر والتقدير
راجع هذه المقالة كلّ من أوستن سولي وإتيان نويل وراشيل أندرو. الصورة الرئيسية تقدّمها كريستينا رامف على Unsplash.