Dosyaları JavaScript'te okuma

Kullanıcının yerel cihazındaki dosyaları seçme ve bu dosyalarla etkileşimde bulunma, web'in en sık kullanılan özelliklerinden biridir. Kullanıcıların dosya seçip bunları bir sunucuya yüklemesine olanak tanır. Örneğin, fotoğraf paylaşırken veya vergi belgeleri gönderirken bu özellikten yararlanılabilir. Ayrıca, sitelerin verileri ağ üzerinden aktarmasına gerek kalmadan okumasına ve değiştirmesine de olanak tanır. Bu sayfada, dosyalarla etkileşim kurmak için JavaScript'in nasıl kullanılacağı açıklanmaktadır.

Modern File System Access API

File System Access API, kullanıcının yerel sistemindeki dosya ve dizinleri okuma ve yazma yöntemi sunar. Chrome ve Edge gibi çoğu Chromium tabanlı tarayıcıda kullanılabilir. Bu API hakkında daha fazla bilgi edinmek için File System Access API başlıklı makaleyi inceleyin.

File System Access API tüm tarayıcılarla uyumlu olmadığından, browser-fs-access kitaplığını kullanmanızı öneririz. Bu yardımcı kitaplık, yeni API'nin kullanılabildiği her yerde bu API'yi kullanır ve kullanılamadığı durumlarda eski yaklaşımlara geri döner.

Dosyalarla klasik yöntemle çalışma

Bu kılavuzda, eski JavaScript yöntemlerini kullanarak dosyalarla nasıl etkileşimde bulunacağınız gösterilmektedir.

Dosya seç

Dosya seçmenin iki temel yolu vardır: HTML giriş öğesini kullanma ve sürükle ve bırak bölgesini kullanma.

HTML giriş öğesi

Kullanıcıların dosya seçmesinin en kolay yolu, tüm büyük tarayıcılarda desteklenen <input type="file"> öğesini kullanmaktır. Tıklandığında, kullanıcının işletim sisteminin yerleşik dosya seçimi kullanıcı arayüzünü kullanarak bir dosya veya multiple özelliği eklenmişse birden fazla dosya seçmesine olanak tanır. Kullanıcı bir veya daha fazla dosya seçmeyi bitirdiğinde öğenin change etkinliği tetiklenir. event.target.files öğesinden dosya listesine erişebilirsiniz. Bu öğe, FileList nesnesidir. FileList içindeki her öğe bir File nesnesidir.

<!-- The `multiple` attribute lets users select multiple files. -->
<input type="file" id="file-selector" multiple>
<script>
  const fileSelector = document.getElementById('file-selector');
  fileSelector.addEventListener('change', (event) => {
    const fileList = event.target.files;
    console.log(fileList);
  });
</script>

Aşağıdaki örnek, kullanıcının işletim sisteminin yerleşik dosya seçimi kullanıcı arayüzünü kullanarak birden fazla dosya seçmesine ve ardından seçilen her dosyayı konsola kaydetmesine olanak tanır.

Kullanıcıların seçebileceği dosya türlerini sınırlama

Bazı durumlarda, kullanıcıların seçebileceği dosya türlerini sınırlamak isteyebilirsiniz. Örneğin, bir resim düzenleme uygulaması yalnızca resimleri kabul etmeli, metin dosyalarını kabul etmemelidir. Dosya türü kısıtlamaları ayarlamak için giriş öğesine accept özelliğini ekleyerek hangi dosya türlerinin kabul edileceğini belirtin:

<input type="file" id="file-selector" accept=".jpg, .jpeg, .png">

Özel sürükleme ve bırakma

Bazı tarayıcılarda <input type="file"> öğesi de bir bırakma hedefidir ve kullanıcıların dosyaları uygulamanıza sürükleyip bırakmasına olanak tanır. Ancak bu bırakma hedefi küçüktür ve kullanımı zor olabilir. Bunun yerine, <input type="file"> öğesini kullanarak temel özellikleri sağladıktan sonra büyük ve özel bir sürükle-bırak alanı sağlayabilirsiniz.

İndirme bölgenizi seçme

Bırakma yüzeyiniz, uygulamanızın tasarımına bağlıdır. Pencerenin yalnızca bir kısmının bırakma yüzeyi olmasını isteyebilirsiniz ancak pencerenin tamamını kullanabilirsiniz.

Bir resim sıkıştırma web uygulaması olan Squoosh&#39;un ekran görüntüsü.
Squoosh, pencerenin tamamını bırakma alanı yapar.

Squoosh adlı resim sıkıştırma uygulaması, kullanıcının bir resmi pencerenin herhangi bir yerine sürüklemesine ve <input type="file"> öğesini çağırmak için select an image (resim seç) seçeneğini tıklamasına olanak tanır. Bırakma bölgesi olarak neyi seçerseniz seçin, kullanıcının dosyaları bu yüzeye sürükleyebileceği açıkça anlaşılmalıdır.

Bırakma bölgesini tanımlama

Bir öğeyi sürükle ve bırak bölgesi olarak etkinleştirmek için iki etkinlik için işleyici oluşturun: dragover ve drop. dragover etkinliği, sürükle ve bırak işleminin dosyanın bir kopyasını oluşturduğunu görsel olarak belirtmek için tarayıcı kullanıcı arayüzünü günceller. drop etkinliği, kullanıcı dosyaları yüzeye bıraktıktan sonra tetiklenir. Giriş öğesinde olduğu gibi, dosya listesine event.dataTransfer.files (FileList nesnesi) üzerinden erişebilirsiniz. FileList içindeki her öğe bir File nesnesidir.

const dropArea = document.getElementById('drop-area');

dropArea.addEventListener('dragover', (event) => {
  event.stopPropagation();
  event.preventDefault();
  // Style the drag-and-drop as a "copy file" operation.
  event.dataTransfer.dropEffect = 'copy';
});

dropArea.addEventListener('drop', (event) => {
  event.stopPropagation();
  event.preventDefault();
  const fileList = event.dataTransfer.files;
  console.log(fileList);
});

event.stopPropagation() ve event.preventDefault() tarayıcının varsayılan davranışını durdurur ve bunun yerine kodunuzun çalışmasına izin verir. Bu işlevler olmadan tarayıcı, kullanıcının tarayıcı penceresine bıraktığı dosyaları açmak için sayfanızdan ayrılırdı.

Canlı gösterim için Özel sürükle ve bırak başlıklı makaleyi inceleyin.

Peki ya dizinler?

Maalesef JavaScript kullanarak bir dizine erişmenin iyi bir yolu yoktur.

<input type="file"> öğesindeki webkitdirectory özelliği, kullanıcının bir veya daha fazla dizin seçmesine olanak tanır. Android için Firefox ve iOS'te Safari hariç çoğu büyük tarayıcıda desteklenir.

Sürükle ve bırak özelliği etkinse kullanıcılar bir dizini bırakma alanına sürüklemeyi deneyebilir. Bırakma etkinliği tetiklendiğinde dizin için bir File nesnesi içerir ancak dizindeki dosyalara erişim sağlamaz.

Dosya meta verilerini okuma

File nesnesi, dosya hakkındaki meta verileri içerir. Çoğu tarayıcı, dosya adı, dosya boyutu ve MIME türü bilgilerini sağlar. Ancak platforma bağlı olarak farklı tarayıcılar farklı veya ek bilgiler sağlayabilir.

function getMetadataForFileList(fileList) {
  for (const file of fileList) {
    // Not supported in Safari for iOS.
    const name = file.name ? file.name : 'NOT SUPPORTED';
    // Not supported in Firefox for Android or Opera for Android.
    const type = file.type ? file.type : 'NOT SUPPORTED';
    // Unknown cross-browser support.
    const size = file.size ? file.size : 'NOT SUPPORTED';
    console.log({file, name, type, size});
  }
}

Bunu input-type-file demoda görebilirsiniz.

Dosya içeriğini okuma

File nesnesinin içeriğini belleğe okumak için FileReader kullanın. FileReader'ya bir dosyayı array buffer, data URL veya metin olarak okumasını söyleyebilirsiniz:

function readImage(file) {
  // Check if the file is an image.
  if (file.type && !file.type.startsWith('image/')) {
    console.log('File is not an image.', file.type, file);
    return;
  }

  const reader = new FileReader();
  reader.addEventListener('load', (event) => {
    img.src = event.target.result;
  });
  reader.readAsDataURL(file);
}

Bu örnekte, kullanıcı tarafından sağlanan bir File okunur, ardından veri URL'sine dönüştürülür ve bu veri URL'si, resmi bir img öğesinde göstermek için kullanılır. Kullanıcının bir resim dosyası seçtiğini nasıl doğrulayacağınızı öğrenmek için read-image-file demosuna bakın.

Dosya okuma işleminin ilerleme durumunu izleme

Büyük dosyaları okurken, kullanıcının okuma işleminin ne kadar ilerlediğini anlaması için kullanıcı deneyimi sunmak faydalı olabilir. Bunun için FileReader tarafından sağlanan progress etkinliğini kullanın. progress etkinliğinin iki özelliği vardır: loaded (okunan miktar) ve total (okunacak miktar).

function readFile(file) {
  const reader = new FileReader();
  reader.addEventListener('load', (event) => {
    const result = event.target.result;
    // Do something with result
  });

  reader.addEventListener('progress', (event) => {
    if (event.loaded && event.total) {
      const percent = (event.loaded / event.total) * 100;
      console.log(`Progress: ${Math.round(percent)}`);
    }
  });
  reader.readAsDataURL(file);
}

Vincent Botta'nın Unsplash'teki lokomotif resmi