Почему событие завершения 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] и читать каждый байт данных, как только они поступают... затем конструировать как требуется.

Другие вопросы по тегам