Przeglądarki już od dawna są w stanie radzić sobie z plikami i katalogami. File API udostępnia funkcje do reprezentowania obiektów plików w aplikacjach internetowych, a także zautomatyzowane wybieranie ich i uzyskiwanie dostępu do ich danych. Jednak gdy przyjrzysz się bliżej, nie wszystko, co się świeci, nie znaczy złoto.
Tradycyjne podejście do plików
Otwieranie plików
Jako deweloper możesz otwierać i odczytywać pliki za pomocą
<input type="file">
.
W najprostszej formie otwarcie pliku może wyglądać jak w przykładzie poniżej.
Obiekt input
daje Ci FileList
,
który w poniższym przypadku składa się tylko z jednego
File
File
to specyficzny rodzaj Blob
,
i być używane w dowolnym kontekście,
w jakim może funkcjonować blob.
const openFile = async () => {
return new Promise((resolve) => {
const input = document.createElement('input');
input.type = 'file';
input.addEventListener('change', () => {
resolve(input.files[0]);
});
input.click();
});
};
Otwieranie katalogów
Aby otwierać foldery (lub katalogi), możesz ustawić
<input webkitdirectory>
.
Poza tym reszta działa tak samo jak powyżej.
Pomimo nazwy z prefiksem dostawcy,
Z webkitdirectory
można korzystać nie tylko w przeglądarkach Chromium i WebKit, ale również w starszej wersji Edge opartej na EdgeHTML oraz w Firefoksie.
Zapisuję pliki (zamiast je pobierać)
Aby zapisać plik, zwykle wystarczy pobrać plik,
który działa dzięki
<a download>
.
.
W przypadku obiektu blob możesz ustawić atrybut href
kotwicy na adres URL blob:
, który można uzyskać z metody
URL.createObjectURL()
.
.
const saveFile = async (blob) => {
const a = document.createElement('a');
a.download = 'my-file.txt';
a.href = URL.createObjectURL(blob);
a.addEventListener('click', (e) => {
setTimeout(() => URL.revokeObjectURL(a.href), 30 * 1000);
});
a.click();
};
Problem
Olbrzymią wadą metody pobierania jest to, że nie ma możliwości utworzenia klasycznej wersji, otwórz →edit→zapisz przepływ, czyli nie ma możliwości zastąpienia oryginalnego pliku. W rezultacie powstaje nowa kopia oryginalnego pliku. w domyślnym folderze Pobrane w systemie operacyjnym po „zapisaniu”.
Interfejs File System Access API
Interfejs File System Access API znacznie ułatwia wykonywanie operacji, a także zapisywanie. Umożliwia też prawdziwe zapisywanie, co oznacza, że nie tylko możesz wybrać, gdzie zapisać plik, ale także zastąpić istniejący plik.
Otwieranie plików
Za pomocą interfejsu File System Access API
otwarcie pliku jest kwestią pojedynczego wywołania metody window.showOpenFilePicker()
.
To wywołanie zwraca uchwyt pliku, z którego można uzyskać rzeczywisty File
za pomocą metody getFile()
.
const openFile = async () => {
try {
// Always returns an array.
const [handle] = await window.showOpenFilePicker();
return handle.getFile();
} catch (err) {
console.error(err.name, err.message);
}
};
Otwieranie katalogów
Otwórz katalog, dzwoniąc
window.showDirectoryPicker()
, który umożliwia wybieranie katalogów w oknie pliku.
Zapisuję pliki
Zapisywanie plików jest podobne.
Na podstawie uchwytu pliku tworzysz strumień z możliwością zapisu w createWritable()
.
potem zapiszesz dane w obiekcie Blob, wywołując metodę write()
strumienia,
i zamknij strumień, wywołując jego metodę close()
.
const saveFile = async (blob) => {
try {
const handle = await window.showSaveFilePicker({
types: [{
accept: {
// Omitted
},
}],
});
const writable = await handle.createWritable();
await writable.write(blob);
await writable.close();
return handle;
} catch (err) {
console.error(err.name, err.message);
}
};
Przedstawiamy dostęp do systemu plików w przeglądarce
Zapewne nie ma to jak w przypadku interfejsu File System Access API, nie jest jeszcze powszechnie dostępna.
Dlatego uważam interfejs File System Access API za progresywne ulepszenie. Dlatego chcę go używać, gdy przeglądarka go obsługuje, a w przeciwnym razie stosować podejście tradycyjne. a jednocześnie nigdy nie karać użytkownika niepotrzebnymi plikami do pobrania z nieobsługiwanego kodu JavaScript. Interfejs browser-fs-access Biblioteka to odpowiedź na to wyzwanie.
Filozofia projektowania
Interfejs File System Access API prawdopodobnie ulegnie zmianie w przyszłości,
interfejs API Browser-fs-access nie jest po nim modelowany.
Oznacza to, że biblioteka nie jest polyfill,
lecz raczej ponyfill.
Możesz (statycznie lub dynamicznie) importować wyłącznie te funkcje, których potrzebujesz, by aplikacja była jak najmniejsza.
Dostępne metody to
fileOpen()
directoryOpen()
i
fileSave()
.
Wewnętrznie funkcja biblioteki wykrywa, czy interfejs File System Access API jest obsługiwany.
a potem zaimportuje odpowiednią ścieżkę kodu.
Korzystanie z biblioteki dostępnej w przeglądarce
Te 3 metody są intuicyjne w użyciu.
Możesz określić akceptowaną przez aplikację mimeTypes
lub plik extensions
oraz ustawić flagę multiple
aby zezwolić na wybór wielu plików lub katalogów albo zabronić tego wyboru.
Szczegółowe informacje znajdziesz tutaj:
dokumentacji interfejsubrowser-fs-access API.
Poniższy przykładowy kod pokazuje, jak otwierać i zapisywać pliki graficzne.
// The imported methods will use the File
// System Access API or a fallback implementation.
import {
fileOpen,
directoryOpen,
fileSave,
} from 'https://unpkg.com/browser-fs-access';
(async () => {
// Open an image file.
const blob = await fileOpen({
mimeTypes: ['image/*'],
});
// Open multiple image files.
const blobs = await fileOpen({
mimeTypes: ['image/*'],
multiple: true,
});
// Open all files in a directory,
// recursively including subdirectories.
const blobsInDirectory = await directoryOpen({
recursive: true
});
// Save a file.
await fileSave(blob, {
fileName: 'Untitled.png',
});
})();
Prezentacja
Powyższy kod możesz zobaczyć w wersji demonstracyjnej w usłudze Glitch. Jej kod źródłowy również jest dostępny w tym miejscu. Ze względów bezpieczeństwa ramki podrzędne z innych domen nie mogą wyświetlać selektora plików, wersji demonstracyjnej nie można umieścić w tym artykule.
Biblioteka FS z dostępem do przeglądarki
W wolnym czasie uczestniczę w programie PWA do zainstalowania o nazwie Excalidraw, narzędzie do wirtualnej tablicy, które pozwala łatwo szkicować diagramy rysunkowe. Jest w pełni elastyczny i dobrze działa na różnych urządzeniach – od małych telefonów komórkowych po komputery z dużymi ekranami. Oznacza to, że musi zajmować się plikami na różnych platformach. niezależnie od tego, czy obsługują interfejs File System Access API. Dzięki temu świetnie nadaje się do wdrożenia biblioteki z dostępem do systemu plików przeglądarki.
Mogę na przykład zacząć rysować na iPhonie, zapisz go (technicznie: pobierz, ponieważ Safari nie obsługuje interfejsu File System Access API). do folderu pobranych plików na iPhonie, otwórz plik na pulpicie (po przesłaniu go z telefonu) modyfikować plik, zastąpić go moimi zmianami, a nawet zapisać jako nowy plik.
. . .Przykładowy kod w rzeczywistości
Poniżej znajdziesz przykładowy kod dostępu z fs przeglądarki używany w Excalidraw.
Ten fragment pochodzi z
/src/data/json.ts
Szczególnie interesujące jest to, w jaki sposób metoda saveAsJSON()
przekazuje uchwyt pliku lub null
na dostęp do funkcji przeglądarki z fs.
fileSave()
, która powoduje zastąpienie po podaniu nicka,
lub zapisać w nowym pliku.
export const saveAsJSON = async (
elements: readonly ExcalidrawElement[],
appState: AppState,
fileHandle: any,
) => {
const serialized = serializeAsJSON(elements, appState);
const blob = new Blob([serialized], {
type: "application/json",
});
const name = `${appState.name}.excalidraw`;
(window as any).handle = await fileSave(
blob,
{
fileName: name,
description: "Excalidraw file",
extensions: ["excalidraw"],
},
fileHandle || null,
);
};
export const loadFromJSON = async () => {
const blob = await fileOpen({
description: "Excalidraw files",
extensions: ["json", "excalidraw"],
mimeTypes: ["application/json"],
});
return loadFromBlob(blob);
};
Uwagi na temat interfejsu
Zarówno w Excalidraw, jak i w aplikacji
interfejs użytkownika powinien dostosowywać się do obsługi używanej przeglądarki.
Jeśli interfejs File System Access API jest obsługiwany (if ('showOpenFilePicker' in window) {}
)
oprócz przycisku Zapisz jako możesz wyświetlać przycisk Zapisz jako.
Zrzuty ekranu poniżej pokazują różnicę między elastycznym głównym paskiem narzędzi aplikacji Excalidraw na iPhonie i w Chrome na komputerze.
Zwróć uwagę, że na iPhonie brakuje przycisku Zapisz jako.
Podsumowanie
Praca z plikami systemowymi jest zasadniczo sprawdzana we wszystkich nowoczesnych przeglądarkach. W przeglądarkach, które obsługują interfejs File System Access API, możesz zwiększyć wygodę użytkowania, zezwalając na do rzeczywistego zapisywania i zastępowania (nie tylko pobierania) plików oraz umożliwiając użytkownikom tworzenie nowych plików w dowolnym miejscu, a jednocześnie funkcjonować w przeglądarkach, które nie obsługują interfejsu File System Access API. browser-fs-access ułatwia życie stawiając na niuanse stopniowego ulepszania i jak najprostsze tworzenie kodu.
Podziękowania
Ten artykuł został zrecenzowany przez Joe Medley i Kayce Basques Dziękujemy współtwórcom Excalidraw za pracę nad projektem i za sprawdzenie moich żądań pull. Baner powitalny – autor: Ilia Pawłow o Unsplash.