File System Standard นำระบบไฟล์ส่วนตัวต้นทาง (OPFS) มาใช้เป็นปลายทางพื้นที่เก็บข้อมูลแบบส่วนตัวสำหรับต้นทางของหน้าเว็บ และจะไม่แสดงแก่ผู้ใช้ที่ให้สิทธิ์เข้าถึงไฟล์พิเศษประเภทพิเศษซึ่งมีการเพิ่มประสิทธิภาพที่สูง
การสนับสนุนเบราว์เซอร์
ระบบไฟล์ส่วนตัวต้นทางรองรับเบราว์เซอร์รุ่นใหม่และได้รับมาตรฐานจากคณะทำงานเทคโนโลยี Web Hypertext Application Technology (WHATWG) ใน File System Living Standard
แรงจูงใจ
เมื่อนึกถึงไฟล์ในคอมพิวเตอร์ ให้คุณนึกถึงลำดับชั้นของไฟล์ ซึ่งหมายถึงไฟล์ที่จัดอยู่ในโฟลเดอร์ ซึ่งคุณสามารถสำรวจด้วย File Explorer ของระบบปฏิบัติการได้ ตัวอย่างเช่น ใน Windows สำหรับผู้ใช้ที่ชื่อ Tom รายการสิ่งที่ต้องทำอาจอยู่ใน 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 จึงแนะนำวิธีเลือก 3 วิธี ได้แก่ showOpenFilePicker()
, showSaveFilePicker()
และ showDirectoryPicker()
ซึ่งทำงานตรงตามชื่อที่แนะนำ โดยจะเปิดใช้ขั้นตอนดังนี้
- เปิด
ToDo.txt
ด้วยshowOpenFilePicker()
และรับออบเจ็กต์FileSystemFileHandle
- จากออบเจ็กต์
FileSystemFileHandle
ให้รับFile
โดยเรียกใช้เมธอดgetFile()
ของแฮนเดิลไฟล์ - แก้ไขไฟล์ จากนั้นเรียกใช้
requestPermission({mode: 'readwrite'})
ที่แฮนเดิล - หากผู้ใช้ยอมรับคำขอสิทธิ์ ให้บันทึกการเปลี่ยนแปลงกลับไปยังไฟล์ต้นฉบับ
- หรือโทรหา
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()
โปรดดูแผนภาพต่อไปนี้ในการเปรียบเทียบระบบไฟล์ที่ผู้ใช้มองเห็นและระบบไฟล์ส่วนตัวต้นทาง แผนภาพแสดงให้เห็นว่านอกเหนือจากไดเรกทอรีรากแล้ว ปัจจัยอื่นๆ ทั้งหมดก็มีแนวคิดเหมือนกัน โดยมีลำดับชั้นของไฟล์และโฟลเดอร์เพื่อจัดระเบียบและจัดเรียงตามความต้องการของข้อมูลและพื้นที่เก็บข้อมูล
ข้อมูลจำเพาะเกี่ยวกับระบบไฟล์ส่วนตัวต้นทาง
ระบบไฟล์ส่วนตัวต้นทางขึ้นอยู่กับข้อจำกัดโควต้าของเบราว์เซอร์ เช่นเดียวกับกลไกพื้นที่เก็บข้อมูลอื่นๆ ในเบราว์เซอร์ (เช่น 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 เลือกแท็บ OPFS Explorer จากนั้นคุณจะพร้อมตรวจสอบลำดับชั้นของไฟล์ บันทึกไฟล์จากระบบไฟล์ส่วนตัวของต้นทางไปยังระบบไฟล์ที่ผู้ใช้มองเห็นได้ โดยคลิกชื่อไฟล์และลบไฟล์และโฟลเดอร์โดยคลิกไอคอนถังขยะ
ข้อมูลประชากร
ดูการใช้งานระบบไฟล์ส่วนตัวต้นทาง (หากคุณติดตั้งส่วนขยาย OPFS Explorer) ในการสาธิตที่ใช้เป็นแบ็กเอนด์สำหรับฐานข้อมูล SQLite ที่คอมไพล์ไปยัง WebAssembly อย่าลืมดูซอร์สโค้ดใน Glitch โปรดทราบว่าเวอร์ชันที่ฝังอยู่ด้านล่างไม่ได้ใช้แบ็กเอนด์ของระบบไฟล์ส่วนตัวต้นทาง (เนื่องจาก iframe เป็นแบบข้ามต้นทาง) แต่เมื่อคุณเปิดการสาธิตในแท็บแยกต่างหาก ก็จะใช้
บทสรุป
ระบบไฟล์ส่วนตัวต้นทางตามที่ระบุไว้โดย WHATWG ได้เปลี่ยนวิถีชีวิตที่เราใช้และโต้ตอบกับไฟล์บนเว็บ การทำเช่นนี้ช่วยเปิดโอกาสให้ใช้ระบบไฟล์ที่ผู้ใช้มองเห็นได้ ซึ่งไม่สามารถทำได้จริง ผู้ให้บริการเบราว์เซอร์รายใหญ่ๆ ทั้งหมด ไม่ว่าจะเป็น Apple, Mozilla และ Google ก็ร่วมงานกับเราและต่างมีวิสัยทัศน์ร่วมกัน การพัฒนาระบบไฟล์ส่วนตัวของต้นทางเป็นความร่วมมือกันเป็นอย่างมาก ส่วนความคิดเห็นจากนักพัฒนาแอปและผู้ใช้ก็มีความสำคัญต่อความก้าวหน้าของการพัฒนาดังกล่าว ขณะที่เราปรับแต่งและปรับปรุงมาตรฐานอย่างต่อเนื่อง เรายินดีรับฟังความคิดเห็นเกี่ยวกับที่เก็บ whatwg/fs ในรูปแบบ "ปัญหา" หรือ "คำขอแบบพุล"
ลิงก์ที่เกี่ยวข้อง
- ข้อกำหนดมาตรฐานของระบบไฟล์
- ที่เก็บแบบมาตรฐานของระบบไฟล์
- File System API ที่มีโพสต์ WebKit ของไฟล์ส่วนตัวตามต้นทาง
- ส่วนขยาย OPFS Explorer
ข้อความแสดงการยอมรับ
บทความนี้ได้รับการตรวจสอบโดย Austin Sully, Etienne Noël และ Rachel Andrew รูปภาพหลักของ Christina Rumpf ใน Unsplash