HTML5 Ajax качване на много големи файлове

Тази кратка бележка описва как да изтеглите много големи файлове (над 2 GB) през браузър. Методът, представен в тази публикация, е добър, защото:

  • Файлът се зарежда асинхронно. По това време на страницата се показва лентата за напредъка (ProgressBar);
  • Файлът се зарежда на части и не се чете изцяло в паметта нито от сървъра, нито от браузъра на клиента;
  • Браузърът повтаря зареждането на секцията, ако предишният опит е бил неуспешен. Това е много полезно при изтегляне на големи файлове през HTTP.

Този метод е лош, тъй като изисква използването на браузър, базиран на Gecko 2.0 или по-нова версия или WebKit. В момента това са браузъри като FireFox 4.0+, SeaMonkey 2.1+ или Google Chrome 11+.

Основна идея

Файлът се чете на парчета, като се използват методите slice (), mozSlice () или webkitSlice () на обекта Blob [2]. След това всяка част се изпраща до сървъра с помощта на обекта sendAsBinary () XMLHttpRequest [1]. Ако частта по някаква причина не се зареди, се прави опит за зареждане на частта отново.

Имайте предвид, че методът slice () на Blob обекта е остарял от Gecko 2.0 (FireFox 4), методът mozSlice () е добавен в Gecko 5.0 (FireFox 5), а методът webkitSlice () е добавен от Google Chrome 11.

Все още в Google Chrome няма метод sendAsBinary () на XMLHttpRequest обект.

fileuploader.js

// Първо, нека дефинираме метода XMLHttpRequest.sendAsBinary (),
// ако не е дефиниран (например за браузъра Google Chrome).

if (! XMLHttpRequest. прототип. sendAsBinary)

XMLHttpRequest. прототип. sendAsBinary = функция (datastr) <
функция byteValue (x) <
връщане x. charCodeAt (0) & 0xff;
>
var ords = масив. прототип. карта. обаждане (datastr, byteValue);
var ui8a = нов Uint8Array (ордове);
това. изпращане (ui8a. буфер);
>
>

/ **
* FileUploader клас.
* @param ioptions Асоциативен масив от опции за зареждане
*/
функция FileUploader (ioptions)

// Позицията, от която ще заредим файла
това. позиция = 0;

// Размер на качения файл
това. размер на файла = 0;

// Blob или File обект (FileList [i])
това. файл = нула;

// Асоциативен масив от опции
това. options = ioptions;

// Ако опцията uploadscript не е дефинирана, върнете null. Невъзможно е
// продължавам, ако тази опция не е посочена.
if (this. options ['uploadscript'] == undefined) връща null;

/ *
* Проверете дали браузърът поддържа необходимите обекти
* @return true, ако браузърът поддържа всички необходими обекти
*/
това. CheckBrowser = функция () <
if (window. File && window. FileReader && window. FileList && window. Blob) return true; else връща false;
>


/ *
* Качете част от файла на сървъра
* @param от Position, от който ще заредим файла
*/
това. UploadPortion = функция (от)

// FileReader обект, ние ще прочетем част от заредения файл в него
var четец = нов FileReader ();

// Текущ обект
var, че = това;

// Позицията, от която ще заредим файла
var loadfrom = от;

// Blob обект, за частично четене на файла
var blob = нула;

// Време за изчакване за функцията setTimeout. С тази функция се осъществява повторно изтегляне
// по време на изчакване (което не е напълно правилно)
var xhrHttpTimeout = null;

/ *
* Събитието се задейства след четене на част от файл във FileReader
* @param evt Събитие
*/
четец. onloadend = функция (evt) <
if (evt. target. readyState == FileReader. DONE)

// Зареждане на идентификатор (за да знаем от страна на сървъра какво да лепим с какво)
xhr. setRequestHeader ("Качване-Id", че. options ['uploadid']);
// Начална позиция във файла
xhr. setRequestHeader ("Част-От", от);
// Порция
xhr. setRequestHeader ("Размер на порцията", че. options ['част']);

// Задаване на време за изчакване
че. xhrHttpTimeout = setTimeout (функция () <
xhr. прекъсване ();
>, това. опции ['изчакване']);

/ *
* Събитие XMLHttpRequest.onProcess. Оказване на лентата на напредъка.
* @param evt Събитие
*/
xhr. качване. addEventListener ("напредък", функция (evt) <
if (evt. lengthComputable)

// Изчисляване на изтеглената сума като процент (с точност до 0,1)
var%Complete = Математика. кръгли ((loadfrom + evt. loaded) * 1000/that. filesize); %Complete/= 10;

// Изчисляване на ширината на синята лента ProgressBar
var ширина = математика. кръгли ((loadfrom + evt. loaded) * 300/that. filesize);

// Променете свойствата на елемента ProgressBar, добавете текст към него
var div1 = документ. getElementById ('cnuploader_progressbar');
var div2 = документ. getElementById ('cnuploader_progresscomplete');

div1. стил. дисплей = 'блок';
div2. стил. дисплей = 'блок';
div2. стил. width = width + 'px';
if (%Попълнете тази. позиция) <
че. UploadPortion (тази. Позиция);
>
друго <
// Ако всички парчета са заредени, уведомете сървъра за това. XMLHttpRequest GET метод,
// PHP скриптът е същият.
var gxhr = нов XMLHttpRequest ();
gxhr. отворен ('GET', че. options ['uploadscript'] + '? action = done', true);

// Задаване на идентификатор на зареждане.
gxhr. setRequestHeader ("Качване-Id", че. options ['uploadid']);

/ *
* Събитие XMLHttpRequest.onLoad. Съобщение в края на изтеглянето за края на изтеглянето на файла:).
* @param evt Събитие
*/
gxhr. addEventListener ("зареждане", функция (evt)

// Ако сървърът не е върнал HTTP статус 200, тогава покажете прозорец със съобщението на сървъра.
if (evt. target. status! = 200) <