Tarayıcılar uzun zamandır dosyalar ve dizinlerle çalışabiliyor. File API, web uygulamalarında dosya nesnelerini temsil etmenin yanı sıra bu nesneleri programatik olarak seçme ve verilerine erişme özellikleri de sunar. Ancak daha yakına baktığınızda parlayan tek şey altın değildir.
Dosyalarla başa çıkmanın geleneksel yolu
Dosyaları açma
Geliştirici olarak, <input type="file">
öğesi aracılığıyla dosyaları açıp okuyabilirsiniz.
En basit haliyle, bir dosya aşağıdaki kod örneğine benzer şekilde görünebilir.
input
nesnesi size bir FileList
verir. Aşağıdaki örnekte bu değer yalnızca bir File
içerir.
File
spesifik bir Blob
türüdür ve Blob'un yapabileceği her bağlamda kullanılabilir.
const openFile = async () => {
return new Promise((resolve) => {
const input = document.createElement('input');
input.type = 'file';
input.addEventListener('change', () => {
resolve(input.files[0]);
});
input.click();
});
};
Dizinleri açma
Klasör (veya dizin) açmak için <input webkitdirectory>
özelliğini ayarlayabilirsiniz.
Bunun dışında, diğer her şey yukarıdakiyle aynı şekilde çalışır.
Satıcı ön ekli adına rağmen webkitdirectory
yalnızca Chromium ve WebKit tarayıcılarında değil, aynı zamanda eski EdgeHTML tabanlı Edge'de ve Firefox'ta da kullanılabilir.
Dosyaları kaydetmek (yerine: indirmek)
Geleneksel olarak, dosya kaydederken yalnızca dosya indirebilirsiniz. Bu işlem, <a download>
özelliği sayesinde yapılabilir.
Blob verildiğinde, bağlantının href
özelliğini URL.createObjectURL()
yönteminden alabileceğiniz bir blob:
URL'si olarak ayarlayabilirsiniz.
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();
};
Sorun
İndirme yaklaşımının büyük bir dezavantajı, klasik bir açık→edit→save akışı gerçekleştirmenin, yani orijinal dosyanın üzerine yazmanın mümkün olmamasıdır. Bunun yerine, "kaydettiğinizde" her işlemde, işletim sisteminin varsayılan İndirilenler klasöründe orijinal dosyanın yeni bir kopyası elde edersiniz.
File System Access API
File System Access API hem açma hem de kaydetme işlemlerini çok daha basit hale getirir. Ayrıca, doğru kaydetmeyi de etkinleştirir. Yani yalnızca dosyanın nereye kaydedileceğini seçmekle kalmaz, aynı zamanda mevcut bir dosyanın üzerine de yazabilirsiniz.
Dosyaları açma
File System Access API ile bir dosyayı açmak için window.showOpenFilePicker()
yöntemine yapılan tek bir çağrı yapılır.
Bu çağrı, gerçek File
değerini getFile()
yöntemiyle alabileceğiniz bir dosya tanıtıcısı döndürür.
const openFile = async () => {
try {
// Always returns an array.
const [handle] = await window.showOpenFilePicker();
return handle.getFile();
} catch (err) {
console.error(err.name, err.message);
}
};
Dizinleri açma
Dosya iletişim kutusunda dizinleri seçilebilir hale getiren window.showDirectoryPicker()
yöntemini çağırarak bir dizin açın.
Dosyalar kaydediliyor
Dosyaları kaydetmek de benzer şekilde basittir.
Dosya tanıtıcısından createWritable()
aracılığıyla yazılabilir bir akış oluşturur, ardından akışın write()
yöntemini çağırarak Blob verilerini yazar ve son olarak close()
yöntemini çağırarak akışı kapatırsınız.
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);
}
};
Tarayıcı fs erişimi ile tanışın
File System Access API her ne kadar sorunsuz olsa da henüz yaygın olarak kullanılmamaktadır.
![File System Access API için tarayıcı destek tablosu. Tüm tarayıcılar "destek yok" veya "bayrağın arkasında" olarak işaretlenir.](https://developer.chrome.google.cn/static/docs/capabilities/browser-fs-access/image/browser-support-table-th-671d3874c04e9.png?authuser=8&hl=tr)
Bu nedenle File System Access API'yi aşamalı bir geliştirme olarak görüyorum. Bu nedenle, tarayıcı desteklediğinde bunu, desteklenmiyorsa geleneksel yaklaşımı kullanmak istiyorum. Tüm bunları yaparken kullanıcıyı desteklenmeyen JavaScript kodunu gereksiz indirmelerle asla cezalandırmamak istiyorum. Bu soruya cevabım browser-fs-access kitaplığıdır.
Tasarım felsefesi
File System Access API'nin ileride değişmesi muhtemel olduğundan, browser-fs-access API'nin modellenmesi mümkün değildir.
Yani kitaplık bir polyfill değil,
bir midilli dolgusu değildir.
Uygulamanızı mümkün olduğunca küçük tutmak için ihtiyacınız olan tüm işlevleri (statik veya dinamik olarak) yalnızca içe aktarabilirsiniz.
Uygun şekilde adlandırılmış fileOpen()
, directoryOpen()
ve fileSave()
yöntemleri kullanılabilir.
Kitaplık özelliği, dahili olarak File System Access API'nin desteklenip desteklenmediğini algılar ve ardından ilgili kod yolunu içe aktarır.
Tarayıcı fs erişim kitaplığını kullanma
Bu üç yöntemin kullanımı kolaydır.
Uygulamanızın kabul edilen mimeTypes
veya extensions
dosyasını belirtebilir ve birden fazla dosya ya da dizinin seçilmesine izin vermek ya da vermemek için bir multiple
işareti ayarlayabilirsiniz.
Tüm ayrıntılar için browser-fs-access API dokümanlarına bakın.
Aşağıdaki kod örneğinde, resim dosyalarını nasıl açıp kaydedebileceğiniz gösterilmektedir.
// 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',
});
})();
Demografi
Glitch'teki demoda yukarıdaki kodu çalışırken görebilirsiniz. İlgili kaynak kodu da burada bulunmaktadır. Güvenlik nedeniyle, çapraz kaynak alt çerçevelerin dosya seçici göstermesine izin verilmediğinden bu makaleye demo yerleştirilemez.
Açık tarayıcı fs-access kitaplığı
Boş zamanlarımda, elle çizilmiş bir hisle kolayca diyagramlar çizmenizi sağlayan bir beyaz tahta aracı olan Excalidraw adlı yüklenebilir bir PWA'ya küçük bir katkıda bulunuyorum. Tamamen duyarlıdır ve küçük cep telefonlarından büyük ekranlı bilgisayarlara kadar çeşitli cihazlarda iyi bir şekilde çalışır. Bu nedenle, File System Access API'yi destekleseler de desteklemeseler de tüm çeşitli platformlardaki dosyalarla ilgilenmeleri gerekir. Bu nedenle, tarayıcı-fs erişim kitaplığı için mükemmel bir adaydır.
Örneğin, iPhone'umda bir çizim başlatabilir, bunu (teknik olarak: Safari File System Access API'yi desteklemediği için indirebilir) iPhone İndirilenler klasörüme indirebilir, dosyayı masaüstümde açabilir (telefonumdan aktardıktan sonra), dosyayı değiştirebilir, değişikliklerimden üzerine yazabilir ve hatta yeni bir dosya olarak kaydedebilirim.
![iPhone'da bir Excalidraw çizimi.](https://developer.chrome.google.cn/static/docs/capabilities/browser-fs-access/image/an-excalidraw-drawing-an-b6a12825381fc.png?authuser=8&hl=tr)
![Masaüstündeki Chrome'daki değiştirilmiş Excalidraw çizimi.](https://developer.chrome.google.cn/static/docs/capabilities/browser-fs-access/image/the-modified-excalidraw-d-43ed0ce25523d.png?authuser=8&hl=tr)
![Değişiklikleri orijinal dosyanın üzerine yazmak.](https://developer.chrome.google.cn/static/docs/capabilities/browser-fs-access/image/overwriting-original-fil-244def5df4bb.png?authuser=8&hl=tr)
![Yeni bir Excalidraw çizim dosyasında yapılan değişiklikler kaydediliyor.](https://developer.chrome.google.cn/static/docs/capabilities/browser-fs-access/image/saving-modifications-a-16addfc23ebbb.png?authuser=8&hl=tr)
Gerçek yaşam kod örneği
Aşağıda, Excalidraw'da kullanılan gerçek bir browser-fs-erişim örneği görebilirsiniz.
Bu alıntı /src/data/json.ts
adresinden alınmıştır.
saveAsJSON()
yönteminin bir dosya tanıtıcısını veya null
'yi browser-fs-access' fileSave()
yöntemine iletmesi özellikle önemlidir. Bu yöntem, herkese açık kullanıcı adı verildiğinde geçersiz kılınmasına veya yoksa yeni bir dosyaya kaydedilmesine neden olur.
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);
};
Kullanıcı arayüzüyle ilgili dikkat edilmesi gereken noktalar
İster Excalidraw ister uygulamanızda, kullanıcı arayüzü
tarayıcının destek durumuna göre uyarlanmalıdır.
File System Access API destekleniyorsa (if ('showOpenFilePicker' in window) {}
) Kaydet düğmesine ek olarak Farklı Kaydet düğmesi de gösterebilirsiniz.
Aşağıdaki ekran görüntülerinde, Excalidraw'un iPhone'daki ve Chrome masaüstündeki duyarlı ana uygulama araç çubuğu arasındaki fark gösterilmektedir.
iPhone'da Farklı Kaydet düğmesinin nasıl yok olduğuna dikkat edin.
![iPhone'da Excalidraw uygulama araç çubuğunu yalnızca "Kaydet" düğmesiyle kullanabilirsiniz.](https://developer.chrome.google.cn/static/docs/capabilities/browser-fs-access/image/excalidraw-app-toolbar-i-f6424de71f2f6.png?authuser=8&hl=tr)
![Chrome masaüstünde, "Kaydet" ve "Farklı Kaydet" düğmeleriyle Excalidraw uygulama araç çubuğu.](https://developer.chrome.google.cn/static/docs/capabilities/browser-fs-access/image/excalidraw-app-toolbar-c-ce0b01551edeb.png?authuser=8&hl=tr)
Sonuçlar
Sistem dosyalarıyla çalışma teknik olarak tüm modern tarayıcılarda çalışır. File System Access API'yi destekleyen tarayıcılarda dosyaların gerçek bir şekilde kaydedilmesine ve üzerine yazılmasına (yalnızca indirmelerine değil) izin vererek ve kullanıcılarınızın istedikleri yerde yeni dosyalar oluşturmasına izin vererek ve File System Access API'yi desteklemeyen tarayıcılarda çalışmaya devam ederek deneyimi daha iyi hale getirebilirsiniz. browser-fs-access, progresif geliştirmenin püf noktalarını ele alarak ve kodunuzu mümkün olduğunca basit hale getirerek hayatınızı kolaylaştırır.
Teşekkür
Bu makale Joe Medley ve Kayce Basques tarafından incelenmiştir. Projedeki çalışmaları ve Çekme İsteklerimi inceledikleri için Excalidraw'a katkıda bulunanlara teşekkür ederim. Ilya Pavlov'un Unsplash'teki hero resmi.