ระบบไฟล์ส่วนตัวต้นทาง

File System Standard นำระบบไฟล์ส่วนตัวต้นทาง (OPFS) มาใช้เป็นปลายทางพื้นที่เก็บข้อมูลแบบส่วนตัวสำหรับต้นทางของหน้าเว็บ และจะไม่แสดงแก่ผู้ใช้ที่ให้สิทธิ์เข้าถึงไฟล์พิเศษประเภทพิเศษซึ่งมีการเพิ่มประสิทธิภาพที่สูง

Thomas Steiner
Thomas Steiner

การสนับสนุนเบราว์เซอร์

ระบบไฟล์ส่วนตัวต้นทางรองรับเบราว์เซอร์รุ่นใหม่และได้รับมาตรฐานจากคณะทำงานเทคโนโลยี Web Hypertext Application Technology (WHATWG) ใน File System Living Standard

การสนับสนุนเบราว์เซอร์

  • 86
  • 86
  • 111
  • 15.2

แหล่งที่มา

แรงจูงใจ

เมื่อนึกถึงไฟล์ในคอมพิวเต��ร์ ให้คุณนึกถึงลำดับชั้นของไฟล์ ซึ่งหมายถึงไฟล์ที่จัดอยู่ในโฟลเดอร์ ซึ่งคุณสามารถสำรวจด้วย File Explorer ของระบบปฏิบัติการได้ ตัวอย่างเช่น ใน 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 จึงแนะนำวิธีเลือก 3 วิธี ได้แก่ showOpenFilePicker(), showSaveFilePicker() และ showDirectoryPicker() ซึ่งทำงานตรงตามชื่อที่แนะนำ โดยจะเปิดใช้ขั้นตอนดังนี้

  1. เปิด ToDo.txt ด้วย showOpenFilePicker() และรับออบเจ็กต์ FileSystemFileHandle
  2. จากออบเจ็กต์ FileSystemFileHandle ให้รับ File โดยเรียกใช้เมธอด getFile() ของแฮนเดิลไฟล์
  3. แก้ไขไฟล์ จากนั้นเรียกใช้ requestPermission({mode: 'readwrite'}) ที่แฮนเดิล
  4. หากผู้ใช้ยอมรับคำขอสิทธิ์ ให้บันทึกการเปลี่ยนแปลงกลับไปยังไฟล์ต้นฉบับ
  5. หรือโทรหา showSaveFilePicker() แล้วให้ผู้ใช้เลือกไฟล์ใหม่ (หากผู้ใช้เลือกไฟล์ที่เปิดไว้ก่อนหน้านี้ ระบบจะเขียนทับเนื้อหาในไฟล์) สำหรับการบันทึกซ้ำ คุณสามารถเก็บแฮนเดิลไฟล์ไว้ได้โดยไม่ต้องแสดงกล่องโต้ตอบการบันทึกไฟล์อีกครั้ง

ข้อจำกัดของการทำงานกับไฟล์บนเว็บ

ไฟล์และโฟลเดอร์ที่เข้าถึงได้ผ่านทางวิธีการเหล่านี้จะทำงานอยู่ในระบบไฟล์ที่ผู้ใช้มองเห็นได้ ไฟล์ที่บันทึกไว้จากเว็บและไฟล์ปฏิบัติการโดยเฉพาะจะมีเครื่องหมายของเว็บกำกับอยู่ ดังนั้นจึงมีคำเตือนเพิ่มเติมที่ระบบปฏิบัติการสามารถแสดงก่อนไฟล์ที่อาจเป็นอันตราย เนื่องจากเป็นฟีเจอร์ความปลอดภัยเพิ่มเติม ไฟล์ที่ได้จากเว็บจะได้รับการปกป้องโดย Google Safe Browsing ด้วย ซึ่งหมายความว่าคุณจะมองว่าเป็นการสแกนไวรัสในระบบคลาวด์ได้อย่างง่ายดาย และในบริบทของบทความนี้ เมื่อเขียนข้อมูลไปยังไฟล์โดยใช้ File System Access API การเขียนจะใช้งานไม่ได้ แต่��ะใช้ไฟล์ชั่วคราว ตัวไฟล์จะไม่ได้รับการแก้ไขเว้นแต่จะผ่านการตรวจสอบความปลอดภัยเหล่านี้ทั้งหมด คุณคงพอจะเข้าใจว่าการดำเนินการนี้จะทำให้ไฟล์ทำงานค่อนข้างช้า แม้จะมีการปรับปรุงเกิดขึ้นหากเป็นไปได้ เช่น ใน macOS อย่างไรก็ตาม การเรียก write() ทุกครั้งจะทำงานด้วยตัวเอง ดังนั้นภายในขั้นสูง ระบบจะเปิดไฟล์ ค้นหาออฟเซ็ตที่ระบุ และเขียนข้อมูลในที่สุด

การใช้ไฟล์เป็นพื้นฐานของการประมวลผล

ในขณะเดียวกัน ไฟล์ก็เป็นวิธีที่ยอดเยี่ยมในการบันทึกข้อมูล ตัวอย่างเช่น SQLite จะจัดเก็บฐานข้อมูลทั้งหมดไว้ในไฟล์เดียว อีกตัวอย่างหนึ่งคือ mipmaps ที่ใช้ในการประมวลผลรูปภาพ Mipmaps จะคำนวณตามลำดับและเพิ่มประสิทธิภาพของภาพ ซึ่งแต่ละภาพจะแสดงความละเอียดต่ำลงเรื่อยๆ ทำให้การดำเนินการหลายอย่าง เช่น การซูมเร็วขึ้น แล้วเว็บแอปพลิเคชันจะได้รับประโยชน์ของไฟล์ แต่ไม่มีค่าใช้จ่ายด้านประสิทธิภาพในการประมวลผลไฟล์บนเว็บได้อย่างไร คำตอบคือระบบไฟล์ส่วนตัวต้นทาง

ระบบไฟล์ส่วนตัวของต้นทางที่ผู้ใช้มองเห็นได้

ระบบไฟล์ส่วนตัวต้นทางไม่แสดงต่อผู้ใช้ ต่างจากระบบไฟล์ที่ผู้ใช้มองเห็นได้ซึ่งเรียกดูโดยใช้ File Explorer ของระบบปฏิบัติการ ไฟล์และโฟลเดอร์ในระบบไฟล์ส่วนตัวต้นทางตามชื่อที่แนะนำ เป็นแบบส่วนตัวและเป็นส่วนตัวมากกว่าสำหรับต้นทางของเว็บไซต์ สำรวจต้นทางของหน้าเว็บโดยพิมพ์ 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() โปรดดูแผนภาพต่อไปนี้ในการเปรียบเทียบระบบไฟล์ที่ผู้ใช้มองเห็นและระบบไฟล์ส่วนตัวต้นทาง แผนภาพแสดงให้เห็นว่านอกเหนือจากไดเรกทอรีรากแล้ว ปัจจัยอื่นๆ ทั้งหมดก็มีแนวคิดเหมือนกัน โดยมีลำดับชั้นของไฟล์และโฟลเดอร์เพื่อจัดระเบียบและจัดเรียงตามความต้องการของข้อมูลและพื้นที่เก็บข้อมูล

แผนภาพของระบบไฟล์ที่ผู้ใช้มองเห็นและระบบไฟล์ส่วนตัวต้นทางที่มีลำดับชั้นไฟล์เป็นข้อยกเว้น 2 ลำดับชั้น จุดแรกเข้าสำหรับระบบไฟล์ที่ผู้ใช้มองเห็นได้คือฮาร์ดดิสก์สัญลักษณ์ ซึ่งจุดแรกเข้าสำหรับระบบไฟล์ส่วนตัวต้นทางจะเรียกเมธอด &#39;navigator.storage.getDirectory&#39;

ข้อมูลจำเพาะเกี่ยวกับระบบไฟล์ส่วนตัวต้นทาง

ระบบไฟล์ส่วนตัวต้นทางขึ้นอยู่กับข้อจำกัดโควต้าของเบราว์เซอร์ เช่นเดียวกับกลไกพื้นที่เก็บข้อมูลอื่นๆ ในเบราว์เซอร์ (เช่น localStorage หรือ IndexedDB) เมื่อผู้ใช้ล้างข้อมูลการท่องเว็บทั้งหมดหรือข้อมูลเว็บไซต์ทั้งหมด ระบบจะลบระบบไฟล์ส่วนตัวต้นทางออกด้วย เรียกใช้ navigator.storage.estimate() และในออบเจ็กต์คำตอบที่เป็นผลลัพธ์ คุณจะเห็นรายการ usage เพื่อดูปริมาณพื้นที่เก็บข้อมูลที่แอปใช้ไปแล้ว ซึ่งจะแยกตามกลไกพื้นที่เก็บข้อมูลในออบเจ็กต์ usageDetails ซึ่งคุณต้องการดูรายการ fileSystem โดยเฉพาะ เนื่องจากระบบไฟล์ส่วนตัวต้นทางจะมองไม่เห็นผู้ใช้ จึงไม่มีข้อความแจ้งเกี่ยวกับสิทธิ์และไม่ม��การตรวจสอบ Google Safe Browsing

การเข้าถึงไดเรกทอรีราก

หากต้องการเข้าถึงไดเรกทอรีราก ให้เรียกใช้คำสั่งต่อไปนี้ สุดท้ายแล้วคุณจะเห็นแฮนเดิลไดเรกทอรีที่ว่างเปล่า โดยเฉพาะ FileSystemDirectoryHandle

const opfsRoot = await navigator.storage.getDirectory();
// A FileSystemDirectoryHandle whose type is "directory"
// and whose name is "".
console.log(opfsRoot);

เทรดหลักหรือ Web Worker

การใช้ระบบไฟล์ส่วนตัวของต้นทางมี 2 วิธี ได้แก่ ในเทรดหลักหรือใน Web Worker Web Workers ไม่สามารถบล็อกเทรดหลักได้ ซึ่งหมายความว่า API ของบริบทนี้สามารถเป็นแบบพร้อมกัน ซึ่งเป็นรูปแบบที่โดยทั่วไปแล้วจะไม่ได้รับอนุญาตในเทรดหลัก API แบบซิงโครนัสทำงานได้เ��็วขึ้นเนื่องจากไม่จำเป็นต้องจัดการกับสัญญา และการดำเนินการไฟล์มักทำพร้อมกันในภาษาเช่น 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']`.

ตรวจสอบว่าแฮนเดิลไฟล์หรือโฟลเดอร์ 2 รายการชี้ไปที่ไฟล์หรือโฟลเดอร์เดียวกันหรือไม่

บางครั้งจะมีแฮนเดิล 2 อันและไม่ทราบว่าแฮนเดิลชี้ไปที่ไฟล์หรือโฟลเดอร์เดียวกันหรือไม่ หากต้องการตรวจสอบว่าเป็นกรณีนี้หรือไม่ ให้ใช้เมธอด 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() จะแสดงเฉพาะในเทรดหลักเท่านั้น แต่ไม่แสดงในเทรดผู้ปฏิบัติงาน โปรดเรียกใช้โค้ดในนั้น

// 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 เพื่อแก้ไขข้อบกพร่องของระบบไฟล์ส่วนตัวของต้นทาง ภาพหน้าจอด้านบนจากส่วนการสร้างไฟล์และโฟลเดอร์ใหม่จะมาจากส่วนขยายโดยตรง

ส่วนขยาย Chrome DevTools ของ OPFS Explorer ใน Chrome เว็บสโตร์

หลังจากติดตั้งส่วนขยายแล้ว ให้เปิดเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome เลือกแท็บ OPFS Explorer จากนั้นคุณจะพร้อมตรวจสอบลำดับชั้นของไฟล์ บันท��กไฟล์จากระบบไฟล์ส่วนตัวของต้นทางไปยังระบบไฟล์ที่ผู้ใช้มองเห็นได้ โดยคลิกชื่อไฟล์และลบไฟล์และโฟลเดอร์โดยคลิกไอคอนถังขยะ

ข้อมูลประชากร

ดูการใช้งานระบบไฟล์ส่วนตัวต้นทาง (หากคุณติดตั้งส่วนขยาย OPFS Explorer) ในการสาธิตที่ใช้เป็นแบ็กเอนด์สำหรับฐานข้อมูล SQLite ที่คอมไพล์ไปยัง WebAssembly อย่าลืมดูซอร์สโค้ดใน Glitch โปรดทราบว่าเวอร์ชันที่ฝังอยู่ด้านล่างไม่ได้ใช้แบ็กเอนด์ของระบบไฟล์ส่วนตัวต้นทาง (เนื่องจาก iframe เป็นแบบข้ามต้นทาง) แต่เมื่อคุณเปิดการสาธิตในแท็บแยกต่างหาก ก็จะใช้

บทสรุป

ระบบไฟล์ส่วนตัวต้นทางตามที่ระบุไว้โดย WHATWG ได้เปลี่ยนวิถีชีวิตที่เราใช้และโต้ตอบกับไฟล์บนเว็บ การทำเช่นนี้ช่วยเปิดโอกาสให้ใช้ระบบไฟล์ที่ผู้ใช้มองเห็นได้ ซึ่งไม่สามารถทำได้จริง ผู้ให้บริการเบราว์เซอร์รายใหญ่ๆ ทั้งหมด ไม่ว่าจะเป็น Apple, Mozilla และ Google ก็ร่วมงานกับเราและต่างมีวิสัยทัศน์ร่วมกัน การพัฒนาระบบไฟล์ส่วนตัวของต้นทางเป็นความร่วมมือกันเป็นอย่างมาก ส่วนความคิดเห็นจากนักพัฒนาแอปและผู้ใช้ก็มีความสำคัญต่อความก้าวหน้าของการพัฒนาดังกล่าว ขณะที่เราปรับแต่งและปรับปรุงมาตรฐานอย่างต่อเนื่อง เรายินดีรับฟังความคิดเห็นเกี่ยวกับที่เก็บ whatwg/fs ในรูปแบบ "ปัญหา" หรือ "คำ��������บพ����"

ข้อความแสดงการยอมรับ

บทความนี้ได้รับการตรวจสอบโดย Austin Sully, Etienne Noël และ Rachel Andrew รูปภาพหลักของ Christina Rumpf ใน Unsplash