Odczytuj pliki w języku JavaScript

Wybieranie plików na urządzeniu lokalnym użytkownika i działanie na nich to jedna z najczęściej używanych funkcji w internecie. Pozwala użytkownikom wybierać pliki i przesyłać je na serwer, np. podczas udostępniania zdjęć lub przesyłania dokumentów podatkowych. Umożliwia też witrynom ich odczytywanie i manipulowanie bez konieczności przesyłania danych przez sieć. Na tej stronie znajdziesz instrukcje korzystania z JavaScriptu do interakcji z plikami.

Nowoczesny interfejs File System Access API

Interfejs File System Access API umożliwia odczytywanie i zapisywanie plików oraz katalogów w systemie lokalnym użytkownika. Jest ona dostępna w większości przeglądarek opartych na Chromium, takich jak Chrome i Edge. Więcej informacji znajdziesz w artykule Interfejs File System Access API.

Ponieważ interfejs File System Access API nie jest zgodny ze wszystkimi przeglądarkami, zalecamy korzystanie z browser-fs-access – biblioteki pomocniczej, która korzysta z nowego interfejsu API wszędzie tam, gdzie jest on dostępny, a gdy jest inaczej, korzysta ze starszych metod.

Praca z plikami w klasyczny sposób

Z tego przewodnika dowiesz się, jak korzystać z plików za pomocą starszych metod JavaScript.

Wybierz pliki

Pliki można wybierać na 2 sposoby: za pomocą elementu wejściowego HTML lub obszaru przeciągania i upuszczania.

Element HTML input

Najprostszym sposobem wybierania plików przez użytkowników jest użycie elementu <input type="file">, który jest obsługiwany we wszystkich popularnych przeglądarkach. Po kliknięciu umożliwia użytkownikowi wybranie pliku lub wielu plików (jeśli uwzględniono atrybut multiple) za pomocą wbudowanego interfejsu użytkownika do wybierania plików w systemie operacyjnym. Gdy użytkownik zakończy wybieranie plików, zostanie uruchomione zdarzenie changeelementu. Możesz uzyskać dostęp do listy plików z event.target.files, która jest obiektem FileList. Każdy element w polu FileList to obiekt 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>

W tym przykładzie użytkownik może wybrać wiele plików za pomocą wbudowanego interfejsu do ich wybierania w systemie operacyjnym, a potem zapisać każdy wybrany plik w konsoli.

Ogranicz typy plików, które użytkownicy mogą wybierać

W niektórych przypadkach możesz chcieć ograniczyć typy plików, które mogą wybierać użytkownicy. Na przykład aplikacja do edycji obrazów powinna akceptować tylko obrazy, a nie pliki tekstowe. Aby ustawić ograniczenia typów plików, dodaj do elementu wejściowego atrybut accept, aby określić akceptowane typy plików:

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

Niestandardowe przeciąganie i upuszczanie

W niektórych przeglądarkach element <input type="file"> umożliwia też użytkownikom przeciąganie plików do aplikacji. Jest on jednak mały i może być trudny w obsłudze. Zamiast tego, po udostępnieniu funkcji podstawowych za pomocą elementu <input type="file"> możesz udostępnić duży, niestandardowy interfejs przeciągania i upuszczania.

Wybierz strefę zrzutu

Powierzchnia dropu zależy od projektu aplikacji. Możesz użyć tylko części okna jako powierzchni do przenoszenia, ale możesz też użyć całego okna.

Zrzut ekranu przedstawiający Squoosh, aplikację internetową do kompresji obrazów.
Squoosh sprawia, że całe okno zmienia się w strefę upuszczania.

Aplikacja do kompresji obrazów Squoosh umożliwia użytkownikowi przeciąganie obrazu w dowolne miejsce okna i kliknięcie wybierz obraz, aby wywołać element <input type="file">. Niezależnie od tego, co wybierzesz jako strefę przenoszenia, upewnij się, że użytkownik wie, że może przeciągać pliki na tę powierzchnię.

Definiowanie strefy upuszczania

Aby umożliwić korzystanie z elementu w postaci strefy do przeciągania i upuszczania, utwórz detektory 2 zdarzeń: dragover i drop. Zdarzenie dragover aktualizuje interfejs przeglądarki, aby wizualnie wskazać, że działanie przeciągania i upuszczania tworzy kopię pliku. Zdarzenie drop uruchamia się, gdy użytkownik upuszcza pliki na powierzchnię. Podobnie jak w przypadku elementu wejściowego, możesz uzyskać dostęp do listy plików z elementu event.dataTransfer.files, który jest obiektem FileList. Każdy element w FileList to obiekt 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() i event.preventDefault() zatrzymują domyślne zachowanie przeglądarki i pozwól na uruchomienie kodu. Bez nich przeglądarka otworzyłaby inną stronę i otwarłaby pliki, które użytkownik przeciągnął do okna przeglądarki.

Instrukcje na żywo znajdziesz w artykule Niestandardowe przeciąganie i upuszczanie.

A katalogi?

Niestety nie ma dobrego sposobu na uzyskanie dostępu do katalogu za pomocą JavaScriptu.

Atrybut webkitdirectory elementu <input type="file"> pozwala użytkownikowi wybrać katalog lub katalogi. Jest obsługiwana w większości głównych przeglądarek, z wyjątkiem Firefoxa na Androida i Safari na iOS.

Jeśli włączone jest przeciąganie i upuszczanie, użytkownik może próbować przeciągnąć katalog do strefy upuszczania. Po wywołaniu zdarzenie drop zawiera obiekt File dla katalogu, ale nie zapewnia dostępu do żadnych plików w katalogu.

Odczytywanie metadanych pliku

Obiekt File zawiera metadane dotyczące pliku. Większość przeglądarek podaje nazwę pliku, jego rozmiar i typ MIME, ale w zależności od platformy różne przeglądarki mogą dostarczać inne lub dodatkowe informacje.

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

Możesz to zobaczyć w działaniu w demo input-type-file.

Czytanie zawartości pliku

Użyj narzędzia FileReader, aby odczytać w pamięci zawartość obiektu File. Możesz zlecić funkcji FileReader odczytanie pliku jako bufora tablic, adresu URL danych lub tekstu:

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

W tym przykładzie odczytujemy File podany przez użytkownika, a następnie konwertujemy go na adres URL danych i używamy tego adresu URL danych do wyświetlania obrazu w elemencie img. Aby dowiedzieć się, jak sprawdzić, czy użytkownik wybrał plik obrazu, zapoznaj się z demo read-image-file.

Monitorowanie postępu odczytu pliku

Podczas odczytu dużych plików warto udostępnić użytkownikowi UX, który informuje użytkownika, jak daleko zaszedł odczyt. Aby to zrobić, użyj zdarzenia progress dostarczonego przez FileReader. Zdarzenie progress ma 2 właściwości: loaded (czytana ilość) i total (ilość do odczytu).

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

Obraz główny autorstwa Vincenta Botty z Unsplash