Odczytuj pliki w języku JavaScript

Wybieranie plików i korzystanie z nich na lokalnym urządzeniu użytkownika 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ęć czy przesyłania dokumentów podatkowych. Umożliwia też witrynom odczytywanie danych i manipulowanie nimi bez konieczności przesyłania danych przez sieć. Na tej stronie pokazujemy, jak używać JavaScriptu do interakcji z plikami.

Nowoczesny interfejs File System Access API

Interfejs File System Access API umożliwia odczyt i zapis w plikach i katalogach w systemie lokalnym użytkownika. Jest dostępny w większości przeglądarek opartych na Chromium, np. Chrome i Edge. Więcej informacji znajdziesz w artykule na temat interfejsu File System Access API.

Interfejs File System Access API nie jest zgodny ze wszystkimi przeglądarkami, dlatego zalecamy użycie browser-fs-access – biblioteki pomocniczej, która korzysta z nowego interfejsu API wszędzie tam, gdzie jest dostępny, i w razie potrzeby powraca do starszych rozwiązań.

Klasyczna praca z plikami

Z tego przewodnika dowiesz się, jak pracować z plikami przy użyciu starszych metod JavaScript.

Wybierz pliki

Są 2 główne sposoby wybierania plików: za pomocą elementu wejściowego HTML oraz strefy przeciągania i upuszczania.

Element wejściowy HTML

Najłatwiejszym sposobem wyboru plików przez użytkowników jest użycie elementu <input type="file">, który jest obsługiwany w każdej popularnej przeglądarce. Po kliknięciu użytkownik może wybrać plik lub kilka plików, jeśli podany jest atrybut multiple w interfejsie wyboru plików systemu operacyjnego. Gdy użytkownik zakończy wybieranie plików, w elemencie uruchamia się zdarzenie change. Listę plików możesz wyświetlić z obiektu event.target.files, który jest obiektem FileList. Każdy element w elemencie FileList jest obiektem 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>

Poniższy przykład pozwala użytkownikowi wybrać wiele plików za pomocą wbudowanego interfejsu wyboru plików systemu operacyjnego, a następnie rejestruje 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 użytkownicy mogą wybierać. Na przykład aplikacja do edycji obrazów powinna akceptować tylko obrazy, a nie pliki tekstowe. Aby ustawić ograniczenia dotyczące typów plików, dodaj do elementu wejściowego atrybut accept i określ 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"> jest także celem zrzutu, który umożliwia użytkownikom przeciąganie i upuszczanie plików do aplikacji. Ta funkcja jest jednak niewielka i może być trudna w obsłudze. Zamiast tego, gdy podasz podstawowe funkcje za pomocą elementu <input type="file">, możesz zapewnić dużą, niestandardową powierzchnię do przeciągania i upuszczania.

Wybierz strefę upuszczania

Powierzchnia upuszczania zależy od konstrukcji aplikacji. Część okna może być tylko powierzchnią, ale możesz wykorzystać całe okno.

Zrzut ekranu aplikacji Squoosh do kompresji obrazów.
Squoosh sprawia, że całe okno jest strefą upuszczania.

Aplikacja Squoosh do kompresji obrazów pozwala przeciągnąć obraz w dowolne miejsce do okna i kliknąć select an image (wybierz obraz), aby wywołać element <input type="file">. Niezależnie od wybranej strefy upuszczania upewnij się, że użytkownik jest informowany o możliwości przeciągania plików na tę platformę.

Zdefiniuj strefę spadku

Aby włączyć dla elementu funkcję przeciągania i upuszczania, utwórz detektory 2 zdarzeń: dragover i drop. Zdarzenie dragover aktualizuje interfejs przeglądarki, aby wskazywać, że przeciąganie i upuszczanie plików tworzy kopię pliku. Zdarzenie drop uruchamia się, gdy użytkownik upuści pliki na powierzchnię. Tak jak w przypadku elementu wejściowego, masz dostęp do listy plików z obiektu event.dataTransfer.files, który jest obiektem FileList. Każdy element FileList jest obiektem 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() zatrzymają domyślne działanie przeglądarki i uruchomią Twój kod. Bez nich przeglądarka w przeciwnym razie opuściłaby stronę i otworzyłaby pliki, które użytkownik przeniósł do okna przeglądarki.

Przykład na żywo znajdziesz w sekcji Niestandardowe przeciąganie i upuszczanie.

A co z katalogami?

Niestety, nie ma dobrego sposobu dostępu do katalogu przy użyciu JavaScriptu.

Atrybut webkitdirectory elementu <input type="file"> pozwala użytkownikowi wybrać katalog lub katalogi. Jest obsługiwana w większości najpopularniejszych przeglądarek. Nie dotyczy to Firefoksa 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 uruchomieniu zdarzenia „drop” zawiera ono obiekt File dla katalogu, ale nie zapewnia dostępu do żadnych plików w katalogu.

Odczytywanie metadanych pliku

Obiekt File zawiera metadane o pliku. Większość przeglądarek podaje nazwę pliku, jego rozmiar i typ MIME, ale zależnie od platformy różne przeglądarki mogą podawać 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 zobaczyć, jak to działa w prezentacji input-type-file.

Odczytywanie zawartości pliku

Aby odczytać zawartość obiektu File w pamięci, użyj narzędzia FileReader. Możesz nakazać usłudze FileReader odczytywanie pliku jako bufora tablicowego, 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);
}

Ten przykład odczytuje parametr File podany przez użytkownika, przekształca go w adres URL danych i używa tego adresu URL do wyświetlenia obrazu w elemencie img. Aby dowiedzieć się, jak sprawdzić, czy użytkownik wybrał plik obrazu, obejrzyj prezentację read-image-file.

Monitorowanie postępu odczytu pliku

Podczas odczytywania dużych plików warto poinformować użytkownika o tym, jak daleko posunął się odczyt. Aby to zrobić, użyj zdarzenia progress udostępnionego przez FileReader. Zdarzenie progress ma 2 właściwości: loaded (ilość odczytu) i total (ilość 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);
}

Baner powitalny autorstwa Vincenta Boty z serii Unsplash