Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   При загрузке файлов перепутываются имена файлов (http://www.flasher.ru/forum/showthread.php?t=173978)

Sergey_S 15.01.2012 16:22

При загрузке файлов перепутываются имена файлов
 
Здравствуйте.
Flash я начал изучать буквально меньше недели назад, поэтому прошу не пинать если что не так). Решил написать мультизагрузчик изображений на сервер с ресайзом на стороне клиента.

Путём проб, ошибок, чтения мануалов и просмотра чужого кода написал код и всё вроде бы работает (фотографии ресайзятся и загружаются), но при загрузке большого количества файлов на сервер, у них(файлов) путаются названия.

К примеру, выбираем файлы: 1.jpg, 2.jpg, 3.jpg, 4.jpg, 5.jpg и загружаем их. На сервере изображение 5.jpg становится 4.jpg, а 1.jpg становится 2.jpg. Возникает ощущение, что эти перепутывания случайны, никакой закономерности не получается обнаружить.

Если загружать 2-3 фотографии, то "перепутываний" названий не происходит.

Сейчас попытаюсь объяснить сам код. По клику по кнопке вызывается метод browse() объекта FileReferenceList. Когда пользователь выбирает файлы, вызывается функция onSelect, в которой запускается цикл с количеством итераций, равным количеству файлов. На каждой итерации создаётся объект FileReference и у него вызывается метод load(), а также в массив ArrayCollection (предназначенный для хранения имён файлов) добавляется элемент с именем файла. На каждой итерации также создаётся addEventListener, который "слушает" загрузку файла во флэш и запускает функцию onLoad(), в которой вызывается метод loadBytes объекта Loader. Далее запускается функция resize() с параметрами BitmapData, размером и именем файла. Элемент с индексом 0 массива ArrayCollection удаляется. Функция resize(), помимо самого ресайза, выполняет и загрузку файлов на сервер.

Вот и сам код:
Код AS3:

        import mx.collections.ArrayCollection;
        import flash.net.URLLoader;
        import flash.net.URLRequest;
        import mx.graphics.codec.JPEGEncoder;
 
        private var fr:FileReferenceList = new FileReferenceList;
        private var reg:RegExp;
        private var fileNames:ArrayCollection = new ArrayCollection; //массив с названиями файлов. Каждый раз из него берётся элемент с индексом 0, затем этот элемент удаляется и так далее
 
        private function onClick():void {
                fr.browse();
                fr.addEventListener(Event.SELECT, onSelect);
        }
 
        private function onSelect(e:Event):void {
                fr.removeEventListener(Event.SELECT, onSelect);
                for (var i:uint = 0; i < fr.fileList.length; i++) {
                      reg = /\.\w+/;
                var fileName:String = fr.fileList[i].name.replace(reg,''); //убираем расширение файла
                fileNames.addItem(fileName); // в массив добавляется название файла
                    var elem:Object = new Object;
                    elem = FileReference(fr.fileList[i]);
                    elem.cancel();
                    elem.load();
                    elem.addEventListener(Event.COMPLETE, onLoad);
                }
          }
 
          private function onLoad(e:Event):void {
              var loader:Loader = new Loader();
              loader.contentLoaderInfo.addEventListener(Event.COMPLETE, afterLoad);
              loader.loadBytes(e.target.data);
          }
 
          private function afterLoad(e:Event):void {
                  var bitmap:Bitmap = e.target.content;
                    var bitmapData:BitmapData = bitmap.bitmapData;
                  var fileName:String = fileNames[0]; //берётся название текущего файла в цикле
                fileNames.removeItemAt(0);//элемент с индексом 0 удаляется, а на его месте создаётся новый для следующего файла на следующей итерации
                resize(bitmapData, 200, fileName);
                resize(bitmapData, 600, fileName);
          }
 
                private function resize(bmd:BitmapData, size:Number, fileName:String):void {
                        var scale:Number;
                        var matrix:Matrix = new Matrix();
                        if (bmd.height > bmd.width) {
                                scale = size / bmd.height;
                        }
                        else {
                                scale = size / bmd.width;
                        }
                        matrix.scale(scale, scale);
                        var minBmd:BitmapData = new BitmapData(bmd.width * scale, bmd.height * scale, true, 0x000000);
                        minBmd.draw(bmd, matrix, null, null, null, true);
                var bmp:Bitmap = new Bitmap(minBmd, PixelSnapping.NEVER, true);
                var jpg:JPEGEncoder = new JPEGEncoder();
                var myBytes:ByteArray = jpg.encode(bmp.bitmapData);
                var uploader:URLLoader = new URLLoader();
                var type:String;
                if (size == 600) {
                        type = "med";
                }
                else {
                        type = "min";
                }
                var request:URLRequest = new URLRequest("uploadFile.php?name="+fileName+"&type="+type);
                var header:URLRequestHeader = new URLRequestHeader("Content-type", "application/octet-stream");
                request.requestHeaders.push(header);
                request.method = URLRequestMethod.POST;
                request.data = myBytes;
                uploader.load(request);
                }

Надеюсь, код понятен.

Возникает впечатление, что цикл переходит на следующую итерацию, не дождавшись, когда выполнятся все функции, запускаемые по elem.addEventListener(Event.COMPLETE, onLoad);, отсюда и путаница в названиях файлов.

В чём может быть проблема? Буду благодарен за любые мысли.

Вместо массива fileNames:ArrayCollection = new ArrayCollection раньше заводил строковую переменную fileName:String, но во всех итерациях цикла эта переменная принимала одно значение.

FlashRus 15.01.2012 16:40

По всей видимости у вас не успевает загрузиться предыдущее изображение и вы начинаете грузить следующее.
Воспользуйтесь рекурсией.

Как только происходит комплит, начинайте грузить следующее изображение, если его номер не превышает общего колличества.


В вашем onSelect запускайте загрузку одного изображения. Слушайте COMPLETE. Как только он произойдёт - начинайте грузить следующее изображение, где опять же начинайте слушать COMPLETE.

Цитата:

Возникает впечатление, что цикл переходит на следующую итерацию, не дождавшись, когда выполнятся все функции, запускаемые по elem.addEventListener(Event.COMPLETE, onLoad);, отсюда и путаница в названиях файлов.
А цикл и не должен ждать. Он просто делает то, что вы в нём напишете. Цикл выполняется фактически мгновенно, а загрузка далеко нет.

И ещё по теме с JPEG. Это работает быстрее, чем использованный вами вариант. Спасибо говорить BlooDHounD

Sergey_S 15.01.2012 16:54

Спасибо большое за ответ! Сейчас попробую реализовать.
upd. Всё, сделал. Также прикрутил кодировщик jpeg blooddy_crypto.swc, действительно, работает заметно быстрее стандартного.

Stitch512 16.01.2012 00:15

А смысл ждать загрузки предыдущего файла чтобы загрузить следующий, как то не по христиански. А если он вообще не загрузится (собака кабеля погрызла), как минимум обработку ошибок добавить надо. А вообще загрузку по хорошему нужно делать параллельно (в этом и смысл слова "мультизагрузчик"). К примеру, Loader вынести в отдельный класс, в котором будет храниться имя файла, тогда по завершению загрузки будет известно какому файлу соответствуют загруженные данные.

Sergey_S 17.01.2012 13:15

Stitch512, у меня стояла цель сделать загрузчик, как ВКонтакте (там же загрузчик последовательно загружает?), чтобы можно было выбрать сразу несколько файлов и последовательно их загрузить. Важна возможность для пользователя редактировать свойства первой и последующих фотографий, пока загружаются остальные. Обработку ошибок само собой добавлю, когда буду запускать проект.

Кстати, ещё вопрос: оправдано ли я поступил, сделав ресайз на стороне клиента для среднего и малого размера? Ведь в этом случае получается, что для одной фотки придётся сделать три аплода (оригинал фото, средняя и миниатюра). Плюс этого решения в том, что серверу не приходится нагружаться для ресайза. Минус - большой трафик.
Можно было бы сделать загрузку сразу оригинала и последующий ресайз уже на сервере, однако это нехило нагружало бы сервер (фотографии будут загружать до 4МБ). В данном случае плюс как раз меньший трафик.

Я так понимаю тот же ВКонтакте использует первый вариант (ресайзит все варианты фото на клиенте и загружает уже готовые на сервер). Я прав?

goodguy 17.01.2012 13:31

Цитата:

оправдано ли я поступил, сделав ресайз на стороне клиента для среднего и малого размера?
Конечно оправдано.
А если клиент загрузит какую-нибудь вообще огромную пикчу? Так будет и трафик большой и нагрузка сервера. Конечно это все лучше делать на машине пользователя. Так по крайней мере уже будут примерно известны размеры всех трех картинок в сумме. И трафик, в большинстве случаев, как раз будет меньше.


Часовой пояс GMT +4, время: 20:24.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.