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

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

دعم المتصفح

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

دعم المتصفح

  • الإصدار 86 من متصفّح Chrome
  • الحافة: 86.
  • Firefox: 111.
  • Safari: الإصدار 15.2.

المصدر

الحافز

عندما تفكر في الملفات الموجودة على جهاز الكمبيوتر، ربما تفكر في التسلسل الهرمي للملفات: وهو الملفات المنظمة في مجلدات يمكنك استكشافها باستخدام مستكشف الملفات في نظام التشغيل الخاص بك. على سبيل المثال، على نظام التشغيل 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 قواعد بيانات كاملة في ملف واحد. ومن الأمثلة الأخرى على استخدام خرائط mipmaps في معالجة الصور. تُعد Mipmaps تسلسلات من الصور محسوبة مسبقًا ومحسّنة، وتمثّل كل منها تمثيلاً بدقة أقل تدريجيًا للصور السابقة، مما يجعل العديد من العمليات مثل التكبير أو التصغير بشكل أسرع. إذًا، كيف يمكن لتطبيقات الويب الاستفادة من مزايا الملفات، ولكن بدون تكاليف أداء معالجة الملفات عبر الويب؟ الإجابة هي نظام الملفات الخاصة المصدر.

النظام المرئي للمستخدم مقابل نظام الملفات الخاص المصدر

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

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

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

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

عرض توضيحي

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

الاستنتاجات

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

شكر وتقدير

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