preface
Consider the following requirements first:
- Is it possible to develop a text editor on the browser to edit local text files?
- Can a Web IDE open a project directory on the hard drive instead of editing files in the cloud?
- A browser version of the video editor, can edit the computer inside the video, audio, pictures, will be synthesized after the film directly stored in the user specified directory?
- Implementing a browser version of file manager?
Whenever the front end hears the operation product to put forward the similar demand, will put forward the question for the first time. When the product describes the requirements, the front end seems to be waiting for the words “click the button to save the file on drive D”. Everything is fine without this sentence, as if the front end has been suffering a great grievance, and this grievance has finally been noticed. Whine that JS is just a “scripting language” that runs in a browser sandbox and is no match for “native languages”.
This was not possible before. But times have changed. Chrome 68 has a new file system API that makes this possible. Now, with permission from the user, JS can manipulate files directly.
Well, this article doesn’t implement a file manager, but it does provide you with the necessary knowledge to implement it.
This section describes file system apis
The compatibility of this batch of API is as follows, currently it is still non-standard, please update your Edge and Chrome before trying.
To quote from Can I Use:
This feature is non-standard and should not be used without careful consideration.
So here we go.
I have an example here (codesandbox.io/s/g3lv1). Due to the… The API does not support calls within iframe, so please open the page separately to browse.
Operations on files (folders) involve three main object bodies: “Folder handle FileSystemDirectoryHandle operation”, “handle file operations FileSystemFileHandle 】 and 【 can write file stream object FileSystemWritableFileStream 】.
So here’s a breakdown of how to get these objects, what methods they provide, and what you can do with them.
Window. ShowDirectoryPicker folders handle FileSystemDirectoryHandle ()
Function: Open the folder selector of the system, and obtain the target folder operation handle after confirming the selection. Users without permission will be prompted to authorize.
There is the following code:
const rootDirHandle = await window.showDirectoryPicker();
Copy the code
After the execution of the effect as shown in the picture, a system folder selector pops up.
Click select and a confirmation popup will appear.After you agree, an icon is displayed on the right of the browser address bar. You can click to view details. You can see that the page has access to the Github directory.After executing this line of code, you get a handle to the folder operation, the rootDirHandle variable.
FileSystemDirectoryHandle. Entries () to get the contents of the folder level directory list file (folder)
There is the following code:
for await (const [key, value] of rootDirHandle.entries()) {
console.log(value)
}
Copy the code
After executing, you can see what directories and files are under the directory, which can only see the contents of the direct children of the directory. Everything can be retrieved by recursion and so on.Key and value.name are file names, and kind tells us whether it’s a folder or a file.
Windows. ShowOpenFilePicker ({}) to get a file handle arrays [FileSystemFileHandle]
Function: open the system file selector, confirm the selection of the target file operation handle array, without permission will prompt users to authorize.
There is the following code:
const fileHandle = await window.showOpenFilePicker(); Window. / / a multiple-choice const fileHandle = await showOpenFilePicker ({multiple: true}); / / select a specific format const fileHandle = await window. ShowOpenFilePicker ({types: [{accept: {/ / MIME types: [file extensions] 'image/PNG' : [], // or 'image/png': [ '.jpg', '.mp4' ], // or 'image/*': ['. PNG ', 'GIF', 'jpeg', 'JPG']}},], / / whether to allow the user to the file selector switch to the filter type to all types (. *) / / to true types must be provided, [] also excludeacceptance: true});Copy the code
ExcludeAcceptAllOption: case of falseExcludeAcceptAllOption: case of true‘image/ PNG ‘: [‘.jpg’, ‘.mp4’] AcceptThis is a union of key and value types that can be selected.
This format restriction is limited to a certain extent, but not eliminated. When the above files are all gray and cannot be selected, use Tab button to switch and you can cut to the files that cannot be selected in gray. Press Enter to select successfully. So the program still needs to determine whether the actual file type is what it expects.
Here the other performance with the window. The showDirectoryPicker consistent, no map.
Window. ShowSaveFilePicker ({}) to save a file and get the file handle FileSystemFileHandle
Function: open the system file selector, save the file to the specified location, before saving can be renamed. Save to get an action handle to this file.
There is the following code:
const options = {
types: [{
accept: { 'text/plain': ['.txt'] },
}],
};
const fileHandle = await window.showSaveFilePicker(options);
Copy the code
The configuration of the options here contents and window. The inside of the showOpenFilePicker is consistent, not repeat.
The results are as follows:After executing the address bar click on the small picture marked with the following tips:As you can see, the advantage of this approach is that there is no user authorization prompt, because once the user saves, the page gets permission to modify the file.
FileSystemDirectoryHandle. GetDirectoryHandle (x, {}) handle FileSystemDirectoryHandle get folder
Gets or creates a new folder in an existing directory and gets its folder handle.
There is the following code:
const testDirHandle = await rootDirHandle.getDirectoryHandle("testDir", {
create: true
});
Copy the code
Previously we selected the Github folder, where rootDirHandle is the handle to the Github folder. After the command is executed, if the github folder contains the testDir folder, the testDirHandle will be the handle of the testDir folder. If the testDir folder does not exist, the testDir folder is created first, and then testDirHandle is the handle to the newly created testDir folder.
FileSystemDirectoryHandle. GetFileHandle (x, {}) get FileSystemFileHandle file handle
Gets or creates a new file in an existing directory and gets a handle to the file.
There is the following code:
/ / get a file handle let txtFileHandle = await rootDirHandle. GetFileHandle (" TXT. TXT ", {create: true});Copy the code
TXT file in github directory, create: true, so if the file does not exist, txt. TXT will be created first.Summary: With a folder handle, you can get or create a new folder or file.
Get File File FileSystemFileHandle. GetFile ()
There is the following code:
/ / get TXT file handle const txtFileHandle = await rootDirHandle. GetFileHandle (" TXT. TXT "); Const txtFile = await txtfilehandle.getfile (); console.log(await txtFile.text());Copy the code
TXT File handle under github folder, and then get TXT File type object. What a File is is not the focus of this article.
FileSystemFileHandle. CreateWritable () to get a writeable file stream FileSystemWritableFileStream
There is the following code:
/ / get TXT file handle const txtFileHandle = await rootDirHandle. GetFileHandle (" TXT. TXT "); / / create a TXT file to write file stream const txtFileWritable = await txtFileHandle. CreateWritable ();Copy the code
When createWritable() is executed, if you do not have permission to modify the folder/file, the browser will prompt you to grant permission.The small icon on the right of the browser address bar will change again after you click to view. The following prompts will appear:
Write the file content FileSystemWritableFileStream. Write (x)
Once you have a writable file stream for the file, you can change the file contents. You can write whatever you want, it’s up to you. Text and images are used as examples.
Example 1: Plain text file
There is the following code:
Write ("haha\nhaha"); // This is a text file, you can use line break, ps: different OS newline may be different await txtFileWritable. // Append the content to await txtFileWritable.write("😄");Copy the code
At this point, we have written content in the TXT file, but if you open the TXT file at this point, you find that there is no content just written, not only that, there is also a temporary file in the folder to record the changes. That’s because I didn’t press Ctrl + S. Where to press to see.If you want to obtain the list of files (folders) in the Github directory, see the following:You can see that the temporary file in Chrome is available. Therefore, avoid operations on temporary files to avoid chrome and program exceptions.
Example 2: Image file
The code is as follows:
/ / get a graphics file blob const imgBlob = await the fetch (" https://unsplash.it/1600/900? random" ).then((res) => res.blob()); Const imgFileName = "img." + imgblob.type.split ("/")[1]; imgFileHandle = await rootDirHandle.getFileHandle(imgFileName, { create: true }); / / create a writeable file stream const imgFileWritable = await imgFileHandle. CreateWritable (); // write image blob await imgfileWritable. write(imgBlob); // Stop writing and save image await imgfileWritable.close (); / / to read it and see again, also can open the folder to view the imgFileHandle = await rootDirHandle. GetFileHandle (imgFileName); Const imgFile = await imgfilehandle.getfile (); Const url = url.createObjecturl (imgFile); // Create blob url const url = url.createObjecturl (imgFile); const img = document.createElement("img"); img.src = url; Img. onload = () => url.revokeobjecturl (url); document.body.appendChild(img);Copy the code
FileSystemWritableFileStream. Close () save writable files flow changes to a file
There is the following code:
// Save the modification to the file await txtFileWritable.close();Copy the code
The close() method is similar to the usual Ctrl + S shortcut. After the above execution, you can see that the temporary file is gone, and our TXT file can also see the content that was just written. At the same time, the image file that was just written is also seen.
FileSystemDirectoryHandle. RemoveEntry (x, {}) deleting files (folders)
You can only create it, but you can’t.
This is the file structure of my current testDir directory.This example deletes the testDir folder in the folder of your choice. Ps: learning materials are deleted can not find me 😝. There is the following code:
/ / recursive file (folder) for the inside of a recursive delete await rootDirHandle. RemoveEntry (testDir, {recursive: true});Copy the code
Recursive: true: recursively delete all contents of the testDir directory. Is there an operation that only deletes a folder but does not retain the contents of that folder?
So I’ll do it at recursive: false. As expected, nothing changed except an error.
But if you think about it a little bit, it works. For example, you just want to delete an empty folder and skip it when there is content.
Then execute the code at recursive: true. All folders and files (folders) within the folder are deleted:Resources that may be useful:
- Github.com/GoogleChrom…
This module allows you to easily use the File System Access API on supporting browsers, with a transparent fallback to the and legacy methods. This library is a ponyfill.
Although encapsulation is done in both ways, because the file system API provides more functionality, the time is still different. But it’s useful because it helps us put less code inside the if else.
An example text editor written by Google Chrome Labs developers.
- excalidraw.com/
A hand-drawn style drawing application. Using file system apis improves the user experience.
- Blog.stackblitz.com/posts/intro…
Running Node in a browser, the Web IDE has the coding experience of a software IDE.
The last
Well, this article doesn’t implement a file manager, but you should now be able to create one yourself.
reference
- MDN Docs. Developer.mozilla.org/en-US/docs/…
- The File System Access API: simplifying Access to local files.web. dev/file-system…
- Introducing WebContainers: Run Node. Js natively in your browser. Blog.stackblitz.com/posts/intro…
- Can I Use. Caniuse.com/?search=sho…
- Browser – FS – Access lib. Github.com/GoogleChrom…
Mowgli focus on the object technology, hand in hand to the cloud of technology