2014-07-18 15 views
18

Pracuję z niestandardowym interfejsem API, aby umożliwić użytkownikowi przesłanie pliku (o, miejmy nadzieję, o dowolnym rozmiarze). Jeśli plik jest zbyt duży, będzie on dzielony na kawałki i obsługiwany na wiele żądań do serwera.Co właściwie robi metoda HTML5 File.slice?

Piszę kod, który używa File i FileReader (HTML5), jak w wielu przykładach z Internetu. W ogóle (z tego co czytałem online) dla chunkfied transferu plików, ludzie najpierw uzyskać blob danych z ich obiektu pliku

var file = $('input[type=file]')[0].files[0]; 
var blob = file.slice(start,end) 

Następnie użyj FileReader przeczytać blob readAsArrayBuffer(blob) lub readAsBinaryString(blob)

I wreszcie w metodzie FileReader.onload(e), wyślij dane do serwera. Powtórz ten proces dla wszystkich porcji w pliku.

Moje pytania są

Dlaczego muszę używać FileReader? Jeśli go nie używam i po prostu wysyłam obiekty BLOB z numerem File.slice, istnieje gwarancja, że ​​operacja krojenia zostanie wykonana przed próbą wysłania danych w każdym żądaniu. Czy obiekt File wczytuje cały plik po jego utworzeniu (na pewno nie?). Czy File.slice szuka pozycji określonej przez parametry, a następnie odczytuje informacje? Dokumentacja nie daje mi wskazówek, jak to jest zaimplementowane.

Odpowiedz

21

Ważne jest, aby pamiętać, że plik dziedziczy po Blobie, plik faktycznie nie ma metody plasterka, pobiera tę metodę z Blob. Plik po prostu dodaje kilka atrybutów metadanych.

Najlepszym sposobem myślenia o Blobie (lub pliku) jest wskazywanie danych, ale nie faktyczne dane. Trochę jak uchwyt pliku w innych językach.

W rzeczywistości nie można uzyskać danych w Blobie bez użycia czytnika, który czyta się asynchronicznie, aby uniknąć blokowania wątku interfejsu użytkownika.

Metoda slice blob() zwraca tylko inny obiekt typu blob, ale znowu to nie dane, to tylko wskaźnik do zakresu danych w obrębie oryginalnego obiektu typu blob, przypominający ograniczony wskaźnik do widoku. Aby faktycznie wydobyć bajty z pokrojonego Bloba, nadal musisz użyć czytnika. W przypadku plasterka typu blob czytnik jest ograniczony.

Jest to tak naprawdę przeznaczone tylko dla wygody, aby nie musieć nosić ze sobą względnych i absolutnych przesunięć w kodzie, można po prostu uzyskać ograniczony widok danych i użyć czytnika tak, jakbyś odczytywano z bajtu 0.

W przypadku XMLHttpRequest (zakładając, że przeglądarka obsługuje nowszy interfejs) dane będą przesyłane strumieniowo przy wysyłaniu i ograniczone przez granię obszaru blob. Zasadniczo będzie działał w ten sam sposób, jaki sobie wyobrazisz, jeśli wysłałeś wskaźnik pliku do metody strumieniowej (co w zasadzie dotyczy tego, co dzieje się pod pokrywami). https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Sending_and_Receiving_Binary_Data#Sending_binary_data

Zasadniczo jest to leniwy czytelnik. Jeśli obiekt blob jest już załadowany/odczytany z systemu plików lub został utworzony w pamięci, po prostu go użyje. Kiedy używasz pliku, będzie on leniwie ładowany i przesyłany asynchronicznie z głównego wątku.

Podstawową logiką jest to, że deweloperzy przeglądarek nigdy nie chcą, aby odczyt stał się synchroniczny, ponieważ mógłby zablokować główny wątek, więc wszystkie API są zaprojektowane wokół tej podstawowej filozofii. Zwróć uwagę, jak Blob.slice() jest zsynchronizowany - w ten sposób wiesz, że tak naprawdę nie wykonuje żadnego IO, tylko ustawia granice i (ewentualnie) wskaźniki plików.

+1

Dziękuję, że definiując plik dla mnie, ma to więcej sensu. Jeśli jednak nadal używam File.Slice (który zwraca blob), a następnie próbuję wysłać ten blob do serwera przy użyciu XMLHttpRequest.send (myBlob), jak/kiedy są dane pobierane z pliku i przekazywane do serwera . Czy może to po prostu zawieść/nie wysłać żadnych danych? - – Ponml

+0

Zaktualizowałem swoją odpowiedź, aby podać trochę więcej szczegółów. Wciągnąłem się w to bardzo głęboko, kiedy pisałem narzędzie javascript rsync: https://github.com/claytongulick/bit-sync –