Модераторы: LSD, AntonSaburov
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> read() и read(b[], 0, b.length) при скачивании. read() работает, в отличие от другого 
:(
    Опции темы
Soir
Дата 12.9.2009, 09:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 7
Регистрация: 15.1.2008

Репутация: нет
Всего: нет



Такой вопрос: не знаю почему, но скачивание файла с read(byte b[], 0, length) не выполняется полностью, в то время как вариант с read() (закомментированный блок) работает как надо. Есть подозрения, что прога просто не успевает до конца прочитать файл,  но, вроде как, она должна ожидать окончания read(b[] ,0, length). как заставить ее это сделать, если ошибка именно в этом? Если нет, то в чем же ошибка?
проверка программы происходила по следующему url:
http://www.coderetard.com/wp-content/uploa...t-msg-thumb.jpg
проверял таймаут по адрему - установлен в 0.
Код

public void run(){

            try{
//                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
//                connection.connect();;
//                in = connection.getInputStream();
//
//                b = new byte[connection.getContentLength()];
//                int pos = 0;
//                while (pos < connection.getContentLength()){
//                    b[pos] = (byte)in.read();
//                    pos++;
//                }
//
//                in.close();
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.connect();
                in = connection.getInputStream();
                b = new byte[connection.getContentLength()];
                in.read(b, 0, b.length);
                in.close();

            }
            catch (IOException e){System.out.println(e.toString()); b = null;}

            System.out.println("File downloaded.");
        }


PM MAIL   Вверх
Galaran
Дата 12.9.2009, 18:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 91
Регистрация: 25.5.2009

Репутация: нет
Всего: 2



Присоединяюсь к вопросу.
Попытался сделать с BufferedInputStream

Код

public class DownloadTest {
      static URL url;

      public static void main(String[] args) throws Throwable {
            url = new URL("http://www.coderetard.com/wp-content/uploads/2009/02/linux-abstract-msg-thumb.jpg");
            
            System.out.println("download by bytes");
            byte[] file1 = downloadByByte();
            System.out.println("Content len = " + file1.length);

            System.out.println("package download");
            byte[] file2 = download();
            System.out.println("Content len = " + file2.length);

            System.out.println("download with buffer");
            byte[] file3 = download();
            System.out.println("Content len = " + file3.length);

            String result = "";
            if (Arrays.equals(file1, file2)) {
                  result = "equals";
            } else {
                  result = "not equals!";
            }

            System.out.println(result);

            result = "";
            if (Arrays.equals(file1, file3)) {
                  result = "equals";
            } else {
                  result = "not equals!";
            }

            System.out.println(result);
      }

      public static byte[] downloadByByte() throws Throwable {
            HttpURLConnection connection = (HttpURLConnection)url.openConnection();
            connection.connect();
            InputStream in = connection.getInputStream();

            byte[] b = new byte[connection.getContentLength()];
            int pos = 0;
            while (pos < connection.getContentLength()) {
                  b[pos] = (byte)in.read();
                  pos++;
            }
            in.close();

            return b;
      }

      public static byte[] download() throws Throwable {
            HttpURLConnection connection = (HttpURLConnection)url.openConnection();
            connection.connect();
            InputStream in = connection.getInputStream();

            byte[] b = new byte[connection.getContentLength()];
            System.out.println("actually readed: " + in.read(b, 0, b.length));
            in.close();

            return b;
      }

      public static byte[] downloadBuffered() throws Throwable {
            HttpURLConnection connection = (HttpURLConnection)url.openConnection();
            connection.connect();
            InputStream in = connection.getInputStream();

            byte[] b = new byte[connection.getContentLength()];
            BufferedInputStream bis = new BufferedInputStream(in, 1024);
            System.out.println("actually readed: " + bis.read(b, 0, b.length));
            in.close();

            return b;
      }
}


Результат:

Код

download by bytes
Content len = 57629
package download
actually readed: 1348
Content len = 57629
download with buffer
actually readed: 1348
Content len = 57629
not equals!
not equals!


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

Код

public static byte[] dynamicRead(InputStream is, int bufferSize) throws IOException {
            byte[] result = null;

            byte[] buffer = new byte[bufferSize];
            int actuallyReaded;
            boolean first = true;
            int nextPos = 0;
            while (true) {
                  actuallyReaded = is.read(buffer);
                  if (first && actuallyReaded == -1) {
                        return null;
                  }
                  if (first && actuallyReaded < bufferSize) {
                        result = new byte[actuallyReaded];
                        System.arraycopy(buffer, 0, result, 0, actuallyReaded);
                        return result;
                  }
                  if (!first) {
                        System.arraycopy(buffer, 0, result, nextPos, actuallyReaded);
                        nextPos += actuallyReaded;
                        if (nextPos == result.length) {
                              return result;
                        } else {
                              continue;
                        }
                  }
                  first = false;
                  result = new byte[is.available() + bufferSize];
                  System.arraycopy(buffer, 0, result, 0, actuallyReaded);
                  nextPos = 0 + bufferSize;
            }
}


Читало по-разному - от 10 до 30 кб, но никогда не прочитывало всё. Удивительно, но при отладке всегда(!) читало всё
Где подвох?
PM MAIL   Вверх
COVD
Дата 12.9.2009, 19:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 11
Всего: 43



При чтении данных из интернета нельзя полагаться на то, что сервер всегда сообщает в HTTP заголовке ответа значение Content-Length, т.е. полную длину данных.

Если обьем ответа достаточно большой, то сервер начинает отсылать данные порциями (чанками). В этом случае полная длина ответа серверу неизвестна в момент начала пересылки. Этот режим называется chunked в HTTP 1.1 . 

При использовании HTTP 1.0 значение Content-Length также может быть неопределено и концом данных является закрытие соединения.

Если же значение Content-Length определено, то надо иметь ввиду, что данные пересылаются порциями, с непредсказуемыми паузами. 

Поэтому универсальным решением является чтение данных до обнаружения их конца.  

Это сообщение отредактировал(а) COVD - 12.9.2009, 19:15
PM MAIL   Вверх
Galaran
Дата 12.9.2009, 23:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 91
Регистрация: 25.5.2009

Репутация: нет
Всего: 2



2 варианта. 1й читает побайтово. 2й читает методом read(byte[]) Подправил свой метод чтения с буффером. В обоих случаях заранее неизвестно сколько байт прийдёт. Поэтому в 1м случае я создаю буффер 5МБ, пишу туда, а потом обрезаю полезную часть. Во втором случае я с каждой итерацией создаю новый массив и копирую содержимое предыдущего и добавляю прочитанную порцию.(Не самый оптимальный способ, но рабочий). В итоге должно получиться 2 одинаковых массива. Чтобы это проверить, я вывожу их длину, сравниваю содержимое и, чтобы наверняка - пишу в jpg файл и потом пробую открыть, как картинку.

Код:
Код

package tests.vingrad;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.ByteBuffer;
import java.util.Arrays;

/**
 *
 * @author galaran
 */
public class DownloadTest {
      static URL url;

      public static void main(String[] args) throws Throwable {
            url = new URL("http://www.coderetard.com/wp-content/uploads/2009/02/linux-abstract-msg-thumb.jpg");

            // read first (byte by byte)
            System.out.println("download by bytes");
            byte[] file = downloadByByte();
            System.out.printf("readed %d bytes\n", file.length);

            // read second (buffered)
            System.out.println("download with buffer");
            byte[] fileBuff = downloadBuffered();
            System.out.printf("readed %d bytes\n", fileBuff.length);

            // compare
            String result = "equals";
            if (!Arrays.equals(file, fileBuff)) {
                  result = "not equals";
            }
            System.out.println(result);

            // save 1th file
            File f = new File(System.getProperty("user.home") + "/bybytes.jpg");
            FileOutputStream fis = new FileOutputStream(f);
            fis.write(file);
            fis.close();

            // save second file
            File fb = new File(System.getProperty("user.home") + "/buffered.jpg");
            fis = new FileOutputStream(fb);
            fis.write(fileBuff);
            fis.close();
      }

      public static byte[] downloadByByte() throws Throwable {
            HttpURLConnection connection = (HttpURLConnection)url.openConnection();
            connection.connect();
            InputStream in = connection.getInputStream();

            ByteBuffer buf = ByteBuffer.allocate(1024 * 1024 * 5); // 5 mb
            int readed;
            int count = 0;
            while ((readed = in.read()) != -1) {
                  count++;
                  buf.put((byte)readed);
            }
            in.close();
            connection.disconnect();

            byte[] result = new byte[count];
            buf.flip();
            buf.get(result, 0, count);

            return result;
      }

      public static byte[] downloadBuffered() throws Throwable {
            HttpURLConnection connection = (HttpURLConnection)url.openConnection();
            connection.connect();
            InputStream in = connection.getInputStream();

            byte[] result = dynamicRead(in, 1024);
            in.close();
            connection.disconnect();

            return result;
      }

      // buffered read until eof
      public static byte[] dynamicRead(InputStream is, int bufferSize) throws IOException {
            byte[] result = new byte[0];

            byte[] buffer = new byte[bufferSize];
            int actuallyReaded;
            int totalReaded = 0;

            int iteration = 0;
            while ((actuallyReaded = is.read(buffer)) != -1) {
                  System.out.println("iteration: " + ++iteration);

                  // readed < buffersize
                  if (actuallyReaded < bufferSize) {
                        System.out.println("Total readed: " + totalReaded + "; readed < buffersize!");
                        if (actuallyReaded == 0)
                              break;
                        result = Arrays.copyOf(result, totalReaded + actuallyReaded);
                        System.arraycopy(buffer, 0, result, totalReaded, actuallyReaded);
                        // totalReaded += actuallyReaded
                        break;
                  }

                  result = Arrays.copyOf(result, totalReaded + actuallyReaded);
                  System.arraycopy(buffer, 0, result, totalReaded, bufferSize);
                  totalReaded += bufferSize;
            }
            return result;
      }
}



В итоге, если запустить, то 1й способ всегда работает, но долго.
2й способ читает только первые 1348 байт

Код

download by bytes
readed 57629 bytes
download with buffer
iteration: 1
iteration: 2
Total readed: 1024; readed < buffersize!
readed 1348 bytes
not equals


Видно, что на 2й итерации уже приходит количество байт, которое поидее должно прийти в самом конце файла.
Куда девается остальная часть файла я не понял

Если запустить в режиме отладки и вручную понажимать эти итерации, то всё нормально.

Код

download by bytes
readed 57629 bytes
download with buffer
iteration: 1
...
iteration: 57
Total readed: 57344; readed < buffersize!
readed 57629 bytes
equals


Разве метод read(byte[]) не обеспечивает блокировку до того момента, пока не прийдёт порция данных? В документации сказано: This method blocks until input data is available, the end of the stream is detected, or an exception is thrown. Вот это мне не понятно почему так происходит.

Это сообщение отредактировал(а) Galaran - 12.9.2009, 23:25
PM MAIL   Вверх
COVD
Дата 13.9.2009, 19:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 11
Всего: 43



Цитата

Разве метод read(byte[]) не обеспечивает блокировку до того момента, пока не прийдёт порция данных?

Обеспечивает. У вас где-то в коде ошибки. 
Возможно это:
 есть totalReaded += bufferSize
 надо totalReaded += actuallyReaded
PM MAIL   Вверх
Galaran
Дата 14.9.2009, 00:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 91
Регистрация: 25.5.2009

Репутация: нет
Всего: 2



Буду искать. 

Код

есть totalReaded += bufferSize; 


не здесь, так как в этом случае количество прочитанных байт всегда равно размеру буффера.
PM MAIL   Вверх
COVD
Дата 14.9.2009, 15:55 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 11
Всего: 43



В этой строке
Код

while ((actuallyReaded = is.read(buffer)) != -1) {

переменная actuallyReaded не всегда принимает значение, равное размеру буфера. Значения actuallyReaded могут быть 1 и больше. Не может быть только 0, потому что если данных нет, то чтение блокируется до поступления очередной порции.  Как только данные поступают из сети, они копируются в buffer и возвращается количество прочитанных байт. И размер порции теоретически может быть и 1 байт.  При обнаружении конца данных read возвращает -1.


Это сообщение отредактировал(а) COVD - 14.9.2009, 15:58
PM MAIL   Вверх
Galaran
Дата 14.9.2009, 18:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 91
Регистрация: 25.5.2009

Репутация: нет
Всего: 2



Воооот оно что...  smile 
Спасибо, жаль + не могу поставить

А я чего-то там мудрил с проверками буффера  smile 


PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: Работа с сетью | Следующая тема »


 




[ Время генерации скрипта: 0.0965 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.