نظام الملفات الخاصة وأصل

يقدّم معيار نظام الملفات نظام الملفات الخاصة المصدر (OPFS) كنقطة نهاية تخزين خاصة بمصدر الصفحة ولا تظهر للمستخدم الذي يوفّر إمكانية الوصول الاختياري إلى نوع خاص من الملفات تم تحسينه بدرجة كبيرة من أجل الأداء.

المتصفحات المتوافقة

تتوافق المتصفّحات الحديثة مع نظام الملفات الخاصة والخاص بالمصدر ويتم توحيده من خلال مجموعة عمل تكنولوجيا تطبيق النص التشعبي (ماذاWG) في File System Living Standard.

التوافق مع المتصفح

  • 86
  • 86
  • 111
  • 15.2

المصدر

الحافز

عندما تفكر في الملفات الموجودة على جهاز الكمبيوتر، ربما تفكر في التسلسل الهرمي للملفات: الملفات المنظمة في مجلدات يمكنك استكشافها باستخدام مستكشف الملفات في نظام التشغيل. على سبيل المثال، على نظام التشغيل Windows، بالنسبة إلى مستخدم يُسمّى Tom، قد تتوفّر قائمة مهامه في C:\Users\Tom\Documents\ToDo.txt. في هذا المثال، ToDo.txt هو اسم الملف، وUsers وTom وDocuments هي أسماء المجلدات. ويمثل `C:` على Windows الدليل الجذري لمحرك الأقراص.

الطريقة التقليدية للتعامل مع الملفات على الويب

لتعديل قائمة المهام في تطبيق ويب، إليك الخطوات المعتادة:

  1. يحمّل المستخدم الملف إلى خادم أو يفتحه في البرنامج من خلال <input type="file">.
  2. يُجري المستخدم تغييراته، ثم ينزِّل الملف الناتج الذي يتضمّن <a download="ToDo.txt> تم إدخاله والذي تم إدخاله آليًا click() من خلال JavaScript.
  3. لفتح المجلدات، يمكنك استخدام سمة خاصة في <input type="file" webkitdirectory>، وعلى الرغم من اسمها، إلا أنها تتوافق عمليًا مع المتصفحات العالمية.

طريقة حديثة للعمل مع الملفات على الويب

لا يمثّل هذا التدفق طريقة تفكير المستخدمين في تعديل الملفات، ما يعني أنّ المستخدمين ينتهي بهم الأمر إلى تنزيل نُسخ من ملفات الإدخال الخاصة بهم. لهذا السبب، قدّمت واجهة File System Access API ثلاث طرق للاختيار، وهي showOpenFilePicker() وshowSaveFilePicker() وshowDirectoryPicker()، وهي الطريقة التي يقترحها أسماؤها. وهي تمكّن التدفق على النحو التالي:

  1. افتح تطبيق "ToDo.txt" باستخدام showOpenFilePicker()، واحصل على عنصر FileSystemFileHandle.
  2. من الكائن FileSystemFileHandle، احصل على File من خلال استدعاء طريقة getFile() للمؤشر الخاص بالملف.
  3. عدِّل الملف، ثم استدعِ requestPermission({mode: 'readwrite'}) على الاسم المعرِّف.
  4. إذا قبِل المستخدم طلب الإذن، احفظ التغييرات إلى الملف الأصلي.
  5. ويمكنك بدلاً من ذلك الاتصال بخدمة showSaveFilePicker() والسماح للمستخدم باختيار ملف جديد. (إذا اختار المستخدم ملفًا سبق فتحه، سيتم استبدال محتواه.) لعمليات الحفظ المتكرّرة، يمكنك الاحتفاظ بمؤشر الملف في التطبيق كي لا تضطر إلى إظهار مربّع حوار حفظ الملف مرّة أخرى.

قيود العمل مع الملفات على الويب

تكون الملفات والمجلدات التي يمكن الوصول إليها بهذه الطرق في نظام يمكن تسميته بنظام الملفات مرئي للمستخدم. يتم تمييز الملفات المحفوظة من الويب والملفات القابلة للتنفيذ على وجه التحديد باستخدام علامة الويب، لذلك هناك تحذير إضافي يمكن أن يعرضه نظام التشغيل قبل تنفيذ ملف يُحتمَل أن يكون خطيرًا. كميزة أمان إضافية، تتم أيضًا حماية الملفات التي يتم الحصول عليها من الويب من خلال ميزة التصفح الآمن، والتي تبسيطًا للأمر وفي سياق هذه المقالة يمكنك اعتباره فحصًا للفيروسات عبر السحابة الإلكترونية. عند كتابة بيانات إلى ملف باستخدام File System Access API، لا تكون عمليات الكتابة في مكانها، ولكن يتم استخدام ملف مؤقت. لا يتم تعديل الملف نفسه ما لم يجتَز جميع فحوصات الأمان هذه. إنّ هذا العمل يبطئ نسبيًا من سرعة عمليات الملفات، على الرغم من تطبيق التحسينات متى أمكن، على سبيل المثال على نظام التشغيل macOS. لا تزال كل استدعاءات write() مستقلة، لذا فهي تفتح الملف تلقائيًا وتنتقل إلى الإزاحة المحددة، ثم تكتب البيانات في النهاية.

الملفات كأساس للمعالجة

في الوقت نفسه، تعد الملفات وسيلة ممتازة لتسجيل البيانات. على سبيل المثال، يخزِّن SQLite قواعد بيانات كاملة في ملف واحد. ومن الأمثلة الأخرى خرائط mipmaps مستخدمة في معالجة الصور. خرائط 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(). للمقارنة بين نظام الملفات المرئية للمستخدم ونظام الملفات الخاصة المصدر، اطّلِع على الرسم البياني التالي. يوضح الرسم التخطيطي أنه بخلاف الدليل الجذري، فإن كل شيء آخر من الناحية النظرية هو نفسه من الناحية النظرية، مع تسلسل هرمي للملفات والمجلدات لتنظيمها وترتيبها حسب الحاجة للبيانات واحتياجات التخزين.

رسم تخطيطي لنظام الملفات المرئية للمستخدم ونظام الملفات الخاصة المصدر مع تسلسلين هرميين نموذجيين للملفات نقطة الدخول لنظام الملفات المرئية للمستخدم هي قرص ثابت رمزي، ونقطة دخول نظام الملفات الخاصة المصدر هي استدعاء الطريقة &quot;navigator.storage.getDirectory&quot;.

مواصفات نظام الملفات الخاصة المصدر

تمامًا مثل آليات التخزين الأخرى في المتصفِّح (مثل 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. لا يمكن للعاملين على الويب حظر سلسلة التعليمات الرئيسية، ما يعني أنّ واجهات برمجة التطبيقات في هذا السياق يمكن أن تكون متزامنة، وهو نمط غير مسموح به عمومًا في سلسلة التعليمات الرئيسية. يمكن أن تكون واجهات برمجة التطبيقات المتزامنة أسرع لأنها تتجنب الاضطرار إلى التعامل مع الوعود، وعادةً ما تكون عمليات الملفات متزامنة في لغات مثل C التي يمكن تجميعها في WebAssembly.

// This is synchronous C code.
FILE *f;
f = fopen("example.txt", "w+");
fputs("Some text\n", f);
fclose(f);

إذا كنت بحاجة إلى أسرع عمليات ممكنة لتشغيل الملفات أو كنت تتعامل مع WebAssembly، انتقِل إلى استخدام نظام الملفات الخاص الأصلي في "عامل تشغيل الويب". وإلا، يمكنك القراءة.

استخدام نظام الملفات الخاصة المصدر في سلسلة التعليمات الرئيسية

إنشاء ملفات ومجلدات جديدة

بعد أن يكون لديك مجلد جذر، أنشِئ الملفات والمجلدات باستخدام الطريقتَين 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

كما وضّحنا سابقًا، لا يمكن لموظفي الويب حظر سلسلة التعليمات الرئيسية، ولهذا السبب يُسمح باستخدام الأساليب المتزامنة في هذا السياق.

الحصول على مقبض وصول متزامن

نقطة الدخول إلى أسرع عمليات ممكنة على الملفات هي 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)، استخدِم إضافة Chrome OPFS Explorer لتصحيح الأخطاء في نظام الملفات الخاص الأصلي. لقطة الشاشة أعلاه من القسم إنشاء ملفات ومجلدات جديدة مأخوذة مباشرةً من الإضافة بالمناسبة.

إضافة OPFS Explorer ضمن &quot;أدوات مطوري البرامج في Chrome&quot; في &quot;سوق Chrome الإلكتروني&quot;

بعد تثبيت الإضافة، افتح "أدوات مطوري البرامج في Chrome"، واختَر علامة التبويب مستكشف OPFS وستصبح جاهزًا لفحص التسلسل الهرمي للملفات. يمكنك حفظ الملفات من نظام الملفات الخاصة المصدر إلى نظام الملفات المرئية للمستخدم من خلال النقر على اسم الملف وحذف الملفات والمجلدات بالنقر على رمز سلة المهملات.

عرض توضيحي

اطّلع على نظام الملفات الخاصة المصدر قيد التنفيذ (في حال تثبيت إضافة OPFS Explorer) في عرض توضيحي يستخدمه كخلفية لقاعدة بيانات SQLite تم تجميعها في WebAssembly. اطّلِع على رمز المصدر على Glitch. يُرجى ملاحظة أنّ الإصدار المضمَّن أدناه لا يستخدم الواجهة الخلفية لنظام الملفات الخاصة المصدر (لأن إطار iframe هو من مصادر متعددة)، ولكن عند فتح العرض التوضيحي في علامة تبويب منفصلة، سيحدث ذلك.

الاستنتاجات

لقد شكّل نظام الملفات الخاصة الأصلي، كما تم تحديده بواسطة WhatWG، طريقة استخدامنا للملفات والتفاعل معها على الويب. وقد أتاح حالات استخدام جديدة كان من المستحيل تحقيقها باستخدام نظام الملفات المرئية للمستخدم. ويعمل جميع مورّدي المتصفّحات الرئيسيين، مثل Apple وMozilla وGoogle، على الانضمام إلى هذا البرنامج ومشاركة رؤية مشتركة. يُعد تطوير نظام الملفات الخاصة المصدر جهدًا تعاونيًا إلى حد كبير، كما أن الملاحظات الواردة من المطوّرين والمستخدمين ضرورية لتحقيق هذا التقدّم. بينما نواصل تحسين المعيار وتحسينه، نرحّب بالملاحظات حول مستودع WhatsApp/fs على شكل "مشاكل" أو "طلبات سحب".

شكر وتقدير

راجعت هذه المقالة أوستن سولي وإتيان نويل وراشيل أندرو. صورة رئيسية من تصوير كريستينا رومف على Unسبلاش