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

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

دعم المتصفح

يتوافق نظام الملفات الخاص بالمصدر مع المتصفّحات الحديثة، وقد وضعت له مجموعة عمل Web Hypertext Application Technology Working Group (WHATWG) معايير موحّدة في معيار نظام الملفات الحي.

Browser Support

  • Chrome: 86.
  • Edge: 86.
  • Firefox: 111.
  • Safari: 15.2.

Source

الحافز

عندما تفكّر في الملفات على جهاز الكمبيوتر، من المحتمل أن تفكّر في تسلسل هرمي للملفات: ملفات منظَّمة في مجلدات يمكنك استكشافها باستخدام مستكشف الملفات في نظام التشغيل. على سبيل المثال، على جهاز Windows، قد تكون قائمة المهام الخاصة بالمستخدم "أحمد" في 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 قواعد البيانات بأكملها في ملف واحد. من الأمثلة الأخرى على ذلك خرائط MIP المستخدَمة في معالجة الصور. خرائط 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. لا يمكن لـ Web Workers حظر سلسلة التعليمات الرئيسية، ما يعني أنّه في هذا السياق، يمكن أن تكون واجهات برمجة التطبيقات متزامنة، وهو نمط غير مسموح به بشكل عام في سلسلة التعليمات الرئيسية. يمكن أن تكون واجهات برمجة التطبيقات المتزامنة أسرع لأنّها تتجنّب التعامل مع الوعود، وعادةً ما تكون عمليات الملفات متزامنة في لغات مثل 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()) {}

عرض محتوى مجلد وجميع المجلدات الفرعية بشكل متكرر

من السهل الوقوع في الخطأ عند التعامل مع الحلقات والدوال غير المتزامنة المقترنة بالتكرار العودي. يمكن أن تكون الدالة أدناه نقطة بداية لإدراج محتويات مجلد وجميع مجلداته الفرعية، بما في ذلك جميع الملفات وأحجامها. يمكنك تبسيط الدالة إذا لم تكن بحاجة إلى أحجام الملفات، وذلك من خلال عدم إرسال الوعد handle.getFile()، بل إرسال handle مباشرةً، في المكان الذي يظهر فيه directoryEntryPromises.push.

  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 Workers حظر سلسلة التعليمات الرئيسية، ولهذا السبب يُسمح في هذا السياق باستخدام الطرق المتزامنة.

الحصول على أداة معالجة الوصول المتزامن

نقطة الدخول إلى أسرع عمليات الملفات الممكنة هي 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 لأدوات مطوّري البرامج في Chrome في &quot;سوق Chrome الإلكتروني&quot;

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

عرض توضيحي

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

الاستنتاجات

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

الإقرارات

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