Почему событие завершения URLStream отправляется, когда файл еще не загружен?
Я пишу приложение для киоска AIR, которое каждую ночь подключается к серверу WordPress, получает файл JSON с путями ко всему контенту, а затем загружает этот контент и сохраняет его на жестком диске киоска.
Есть несколько сотен файлов (jpg, png, f4v, xml), и большинство из них загружаются / сохраняются без проблем. Однако есть два файла f4v, которые никогда не загружаются полностью. Событие complete отправляется, но если я сравниваю bytesTotal (из события progress) с bytesAvailable (из события complete), они не совпадают; bytesTotal больше. BytesTotal (из события progress) совпадает с байтами на сервере.
Значение bytesLoaded в событии progress никогда не увеличивается до уровня, совпадающего с bytesTotal, поэтому я также не могу полагаться на событие progress. Кажется, это происходит каждый раз на одних и тех же двух видео. Видео не очень большие, один 13 МБ, а другой 46 МБ. У меня есть большие видео, которые скачиваются без проблем.
РЕДАКТИРОВАТЬ: После перезагрузки моего компьютера, два видео теперь заканчивают загрузку, но у меня та же проблема с png-файлом размером 300 КБ.
Если я вставлю URL в Firefox, он загрузится правильно. Я также написал простое приложение на C# для загрузки файлов, и оно может загружать их без проблем, поэтому, похоже, это проблема с Flash/AIR.
РЕДАКТИРОВАТЬ: вот более простая версия кода, это из тестового проекта, и это единственный код (URL находится в нашей локальной сети, поэтому вы не сможете загрузить файл самостоятельно):
package {
import flash.display.Sprite;
import flash.events.Event;
import flash.events.ProgressEvent;
import flash.net.URLRequest;
import flash.net.URLStream;
[SWF(backgroundColor="#000000", frameRate="24", width="640", height="480")]
public class Test extends Sprite {
private var fileSize:Number;
private var stream : URLStream;
private var url:String = "http://192.168.150.219/wordpress2/wp-content/uploads/2012/12/John-Butler-clip1.f4v";
public function Test() {
if (stage)
init();
else
this.addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event=null):void {
this.removeEventListener(Event.ADDED_TO_STAGE, init);
stream = new URLStream();
stream.addEventListener(ProgressEvent.PROGRESS, onLoadProgress);
stream.addEventListener(Event.COMPLETE, onLoadComplete);
stream.load(new URLRequest(url));
}
private function onLoadProgress(event:ProgressEvent):void {
fileSize = event.bytesTotal;
var percent:Number = event.bytesLoaded / event.bytesTotal * 100;
trace(percent + "%"); // this never gets to 100%
}
private function onLoadComplete(event:Event):void {
trace("loaded", stream.bytesAvailable, "of", fileSize);
// outputs "loaded 13182905 of 13184365"
// so why is it "complete" when it isn't fully downloaded?
}
}
}
3 ответа
Если у кого-то есть такая же проблема, как у меня. Оказалось, что это проблема кэширования, которая присутствует и в AIR, поэтому временная метка, добавленная к запросу, решает это: http://www.newtonflash.com/blog/as3/prevent-xml-caching-problem/
{
var xmlPath:String="replaceYourXMLPathHere.xml"
var urlReq:URLRequest = new URLRequest(xmlPath+"?time=" + new Date().getTime());
}
Не сравнивать с bytesAvailable
использовать length
вместо. BytesAvailable на самом деле ByteArray.length - ByteArray.position
, Таким образом, если позиция в ByteArray сместилась с индекса 0, значение bytesAvailable уменьшится. Длина всегда будет общим количеством байтов в массиве.
Попробуйте сравнить с использованием длины и посмотреть, если это имеет какое-либо значение. У меня нет времени, чтобы просмотреть ваш код, чтобы увидеть, меняете ли вы позицию в любой момент (целенаправленно или случайно; вы можете сделать это несколькими способами), так что это лучшее, что я могу предложить прямо сейчас.
Ваш ответ в вашем вопросе.
Обычные URL (файлы) - для этого сервера это блок данных. Как только сервер доставляет "блок данных", процесс доставки считается "ЗАВЕРШЕННЫМ". В этом случае, если размер файла составляет 100 КБ, после получения 100 КБ - Flash рассматривает это как "ЗАВЕРШЕНО".
URLStream - для сервера это [ДВА] блока данных (очень простой способ посмотреть на это). Сервер сначала подает СОЕДИНЕНИЕ к потоку... затем передает ДАННЫЕ ПОТОКА. Это обрабатывается во Flash так же, как описано.
Flash будет считать загрузку CONNECTION "ЗАВЕРШЕННОЙ", и НИКОГДА не проверять, загружены ли данные STREAM, - это зависит от вашего сервера. В любых потоках вы должны на самом деле проверять событие [load progress] и читать каждый байт данных, как только они поступают... затем конструировать как требуется.