Membaca file di JavaScript

Memilih dan berinteraksi dengan file di perangkat lokal pengguna adalah salah satu fitur web yang paling umum digunakan. Fitur ini memungkinkan pengguna memilih file dan menguploadnya ke server, misalnya, saat berbagi foto atau mengirimkan dokumen pajak. Hal ini juga memungkinkan situs membaca dan memanipulasinya tanpa harus mentransfer data di seluruh jaringan. Halaman ini membahas cara menggunakan JavaScript untuk berinteraksi dengan file.

File System Access API modern

File System Access API menyediakan cara untuk membaca dari dan menulis ke file serta direktori di sistem lokal pengguna. Fitur ini tersedia di sebagian besar browser berbasis Kromium seperti Chrome dan Edge. Untuk mempelajarinya lebih lanjut, lihat File System Access API.

Karena File System Access API tidak kompatibel dengan semua browser, sebaiknya gunakan browser-fs-access, library helper yang menggunakan API baru di mana pun tersedia dan akan kembali ke pendekatan lama padahal tidak.

Bekerja dengan file dengan cara klasik

Panduan ini menunjukkan cara berinteraksi dengan file menggunakan metode JavaScript lama.

Pilih file

Ada dua cara utama untuk memilih file: menggunakan elemen input HTML, dan menggunakan zona tarik lalu lepas.

Elemen input HTML

Cara termudah bagi pengguna untuk memilih file adalah menggunakan elemen <input type="file">, yang didukung di setiap browser utama. Saat diklik, hal ini memungkinkan pengguna memilih file, atau beberapa file jika atribut multiple disertakan, menggunakan UI pemilihan file bawaan sistem operasi mereka. Setelah pengguna selesai memilih satu atau beberapa file, peristiwa change elemen akan diaktifkan. Anda dapat mengakses daftar file dari event.target.files, yang merupakan objek FileList. Setiap item dalam FileList adalah objek File.

<!-- 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>

Contoh berikut memungkinkan pengguna memilih beberapa file menggunakan UI pemilihan file bawaan sistem operasi mereka, lalu mencatat setiap file yang dipilih ke konsol.

Membatasi jenis file yang dapat dipilih pengguna

Dalam beberapa kasus, Anda mungkin ingin membatasi jenis file yang dapat dipilih pengguna. Misalnya, aplikasi pengeditan gambar hanya boleh menerima gambar, bukan file teks. Untuk menetapkan batasan jenis file, tambahkan atribut accept ke elemen input untuk menentukan jenis file mana yang diterima:

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

Tarik lalu lepas kustom

Di beberapa browser, elemen <input type="file"> juga merupakan target operasi lepas, sehingga pengguna dapat menarik lalu melepas file ke aplikasi Anda. Namun, target operasi lepas ini berukuran kecil dan mungkin sulit digunakan. Sebagai gantinya, setelah menyediakan fitur inti menggunakan elemen <input type="file">, Anda dapat menyediakan platform tarik lalu lepas kustom yang besar.

Pilih zona penurunan

Permukaan operasi lepas bergantung pada desain aplikasi Anda. Anda mungkin hanya ingin sebagian jendela menjadi permukaan lepas, tetapi Anda dapat menggunakan seluruh jendela.

Screenshot Squoosh, aplikasi web kompresi gambar.
Warna Squoosh membuat seluruh jendela menjadi zona lepas.

Aplikasi kompresi gambar Squoosh memungkinkan pengguna menarik gambar di mana saja ke jendela, lalu mengklik select an image untuk memanggil elemen <input type="file">. Apa pun yang Anda pilih sebagai zona lepas, pastikan pengguna dapat menarik file ke platform tersebut dengan jelas.

Menentukan zona pelepasan

Untuk mengaktifkan elemen sebagai zona tarik lalu lepas, buat pemroses untuk dua peristiwa: dragover dan drop. Peristiwa dragover mengupdate UI browser untuk menunjukkan secara visual bahwa tindakan tarik lalu lepas membuat salinan file. Peristiwa drop diaktifkan setelah pengguna meletakkan file ke platform. Seperti elemen input, Anda dapat mengakses daftar file dari event.dataTransfer.files, yang merupakan objek FileList. Setiap item dalam FileList adalah objek File.

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() dan event.preventDefault() menghentikan perilaku default browser dan membiarkan kode Anda berjalan. Tanpa tanda itu, browser akan keluar dari halaman Anda dan membuka file yang diletakkan pengguna di jendela browser.

Untuk demonstrasi langsung, lihat Tarik lalu lepas kustom.

Bagaimana dengan direktori?

Sayangnya, tidak ada cara yang baik untuk mengakses direktori menggunakan JavaScript.

Atribut webkitdirectory pada elemen <input type="file"> memungkinkan pengguna memilih direktori atau direktori. Browser ini didukung di sebagian besar browser utama kecuali Firefox untuk Android dan Safari di iOS.

Jika fitur tarik lalu lepas diaktifkan, pengguna mungkin mencoba menarik direktori ke zona lepas. Saat peristiwa lepas diaktifkan, peristiwa ini akan menyertakan objek File untuk direktori, tetapi tidak memberikan akses ke file mana pun dalam direktori.

Membaca metadata file

Objek File berisi metadata tentang file. Sebagian besar browser memberikan nama file, ukuran file, dan jenis MIME, meskipun bergantung pada platformnya, browser yang berbeda mungkin memberikan informasi yang berbeda atau tambahan.

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});
  }
}

Anda dapat melihat cara kerjanya di demo input-type-file.

Membaca konten file

Gunakan FileReader untuk membaca konten objek File ke dalam memori. Anda dapat memberi tahu FileReader untuk membaca file sebagai buffer array, URL data, atau teks:

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);
}

Contoh ini membaca File yang disediakan oleh pengguna, lalu mengonversinya menjadi URL data, dan menggunakan URL data tersebut untuk menampilkan gambar dalam elemen img. Untuk mempelajari cara memverifikasi bahwa pengguna telah memilih file gambar, lihat demo read-image-file.

Memantau progres pembacaan file

Saat membaca file berukuran besar, sebaiknya berikan beberapa UX untuk memberi tahu pengguna seberapa jauh progres pembacaannya. Untuk itu, gunakan peristiwa progress yang disediakan oleh FileReader. Peristiwa progress memiliki dua properti: loaded (jumlah yang dibaca) dan total (jumlah yang akan dibaca).

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);
}

Banner besar oleh Vincent Botta dari Unsplash