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. Umożliwia użytkownikom wybieranie plików i przesyłanie ich na serwer, na przykład podczas udostępniania zdjęć lub przesyłania dokumentów podatkowych. Umożliwia też witrynom odczytywanie plików cookie i modyfikowanie ich 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 używanie biblioteki pomocniczej browser-fs-access, która korzysta z nowego interfejsu API wszędzie tam, gdzie jest on dostępny, a w przeciwnym razie stosuje starsze metody.

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

Ograniczanie typów plików, które użytkownicy mogą wybierać

W niektórych przypadkach możesz 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 dotyczące typu pliku, dodaj atrybut accept do elementu wejściowego, aby określić, które typy plików są akceptowane:

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

Niestandardowe przeciąganie i upuszczanie

W niektórych przeglądarkach element <input type="file"> jest też obszarem przeciągania i upuszczania, co pozwala użytkownikom przeciągać i upuszczać pliki w aplikacji. Ten obszar jest jednak mały i może być trudny w użyciu. 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 aplikacji internetowej Squoosh do kompresji obrazów.
Pliki można przeciągać do dowolnego miejsca w oknie.

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ę.

Określanie obszaru przenoszenia

Aby umożliwić przeciąganie i upuszczanie elementów, utwórz odbiorniki dla 2 zdarzeń: dragoverdrop. Zdarzenie dragover aktualizuje interfejs przeglądarki, aby wizualnie wskazać, że działanie przeciągania i upuszczania tworzy kopię pliku. Zdarzenie drop jest wywoływane, gdy użytkownik przeciągnie 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()event.preventDefault() zatrzymają domyślne zachowanie przeglądarki i zamiast tego pozwolą 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.

Aby zobaczyć demonstrację, zapoznaj się z artykułem 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 przeciąganie i upuszczanie jest włączone, użytkownik może spróbować przeciągnąć katalog do strefy upuszczania. Gdy zdarzenie drop zostanie wywołane, zawiera ono 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 udostępnia nazwę pliku, jego rozmiar i typ MIME, ale w zależności od platformy różne przeglądarki mogą udostępniać 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 funkcji FileReader, aby odczytać zawartość obiektu File do pamięci. Możesz zlecić 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ępów odczytu pliku

Podczas odczytu dużych plików przydatne może być wyświetlanie użytkownikowi informacji o tym, jak daleko zaawansował odczyt. W tym celu użyj zdarzenia progress udostępnianego 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