Dosyaları JavaScript'te okuma

Kullanıcının yerel cihazındaki dosyaları seçmek ve bu dosyalarla etkileşimde bulunmak, web'de en sık kullanılan özelliklerden biridir. Kullanıcıların dosya seçmesine ve örneğin fotoğraf paylaşırken veya vergi belgelerini gönderirken bir sunucuya yüklemesine olanak tanır. Ayrıca, sitelerin verileri ağ genelinde aktarmak zorunda kalmadan bunları okumasına ve değiştirmesine de olanak tanır. Bu sayfada, dosyalarla etkileşimde bulunmak için JavaScript'in nasıl kullanılacağı ayrıntılı bir şekilde açıklanmaktadır.

Modern File System Access API

File System Access API, kullanıcının yerel sistemindeki dosyalardan ve dizinlere okuma ve yazma yöntemi sunar. Chrome ve Edge gibi Chromium tabanlı tarayıcıların çoğunda mevcut. Bu özellik hakkında daha fazla bilgi edinmek için File System Access API'yi inceleyin.

File System Access API tüm tarayıcılarla uyumlu olmadığından, kullanılabilir olduğu her yerde yeni API'yi kullanan ve kullanılamadığında eski yaklaşımlara geri dönen bir yardımcı kitaplık olan browser-fs-access'i kullanmanızı öneririz.

Klasik yöntemle dosyalarla çalışın

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

Dosyaları seçin

Dosyaları seçmek için iki temel yöntem vardır: HTML giriş öğesini kullanma ve sürükle ve bırak bölgesi kullanma.

HTML giriş öğesi

Kullanıcıların dosya seçmesinin en kolay yolu, yaygın olarak kullanılan tüm tarayıcılarda desteklenen <input type="file"> öğesini kullanmaktır. Bu özellik tıklandığında kullanıcının, işletim sisteminin yerleşik dosya seçimi kullanıcı arayüzünü kullanarak bir veya multiple özelliği eklenmişse birden fazla dosya seçmesine olanak tanır. Kullanıcı bir dosya veya dosyayı seçmeyi bitirdiğinde, öğenin change etkinliği tetiklenir. Bir FileList nesnesi olan event.target.files alanındaki dosya listesine erişebilirsiniz. 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 sistemlerinin 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ırlayın

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 etmelidir, metin dosyalarını kabul etmemelidir. Dosya türü kısıtlamaları ayarlamak için giriş öğesine bir accept özelliği ekleyerek hangi dosya türlerinin kabul edildiğini belirtin:

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

Özel sürükle ve bırak

Bazı tarayıcılarda <input type="file"> öğesi aynı zamanda bir bırakma hedefidir ve kullanıcıların uygulamanıza dosya 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"> öğesi kullanarak temel özellikleri sağladıktan sonra büyük, özel bir sürükle ve bırak yüzeyi sağlayabilirsiniz.

Lansman bölgenizi seçin

Damla yüzeyiniz, uygulamanızın tasarımına bağlıdır. Pencerenin yalnızca bir bölümünün düşme yüzeyi olmasını isteyebilirsiniz, ancak tüm pencereyi kullanabilirsiniz.

Resim sıkıştırma web uygulaması olan Squoosh&#39;un ekran görüntüsü.
Squoosh, tüm pencereyi bırakma bölgesine dönüştürür.

Resim sıkıştırma uygulaması Squoosh, kullanıcının pencerenin herhangi bir yerine resim sürüklemesini ve <input type="file"> öğesini çağırmak için bir resim seç'i tıklamasını sağlar. Açılır bölgeniz olarak ne seçerseniz seçin, kullanıcının dosyaları bu yüzeye sürükleyebileceklerinin açıkça anlaşıldığından emin olun.

Bırakma bölgesini tanımlama

Bir öğeyi sürükleyip bırakma bölgesi olarak etkinleştirmek için iki etkinlik için işleyiciler oluşturun: dragover ve drop. dragover etkinliği, sürükle ve bırak işleminin dosyanın bir kopyasını oluşturmakta olduğunu görsel olarak belirtmek için tarayıcı kullanıcı arayüzünü günceller. Kullanıcı dosyaları yüzeye bıraktıktan sonra drop etkinliği tetiklenir. Giriş öğesinde olduğu gibi, bir FileList nesnesi olan event.dataTransfer.files nesnesindeki dosya listesine de 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ı durdurun ve bunun yerine kodunuzun çalışmasına izin verin. Aksi halde, tarayıcı sayfanızdan ayrılır ve kullanıcının tarayıcı penceresine bıraktığı dosyaları açar.

Canlı demo için Özel sürükle ve bırak bölümüne bakın.

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 dizin veya dizin seçebilmesini sağlar. Android için Firefox ve iOS için Safari dışındaki çoğu büyük tarayıcıda desteklenir.

Sürükle ve bırak özelliği etkinse bir kullanıcı, bir dizini bırakma bölgesine sürüklemeyi deneyebilir. Bırakma etkinliği etkinleştiğinde, dizin için bir File nesnesi içerir ancak dizindeki hiçbir dosyaya erişim sağlamaz.

Dosya meta verilerini okuma

File nesnesi dosyayla ilgili meta verileri içerir. Çoğu tarayıcı dosya adını, dosyanın boyutunu ve MIME türünü sağlar. Bununla birlikte, 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});
  }
}

input-type-file demosunda bunu uygulamalı olarak görebilirsiniz.

Dosya içeriğini okuma

Bir File nesnesinin içeriğini belleğe okumak için FileReader kullanın. FileReader adlı kullanıcıya bir dosyayı dizi arabelleği, veri URL'si 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 bunu bir veri URL'sine dönüştürür ve resmi bir img öğesinde göstermek için bu veri URL'sini kullanı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 ilerlemesini izleme

Büyük dosyaları okurken, kullanıcıya okumanın ne kadar ilerlediğini bildirmek için birtakım kullanıcı deneyimi sunmak yararlı 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);
}

Unsplash'tan Vincent Botta'nın hero resmi