2009-03-04 12 views
1

Я пытаюсь читать удаленного двоичного файла (например, изображение) из Интернета, как это:Неожиданный результат от HttpURLConnection - чтение удаленного двоичного файла

HttpURLConnection connection = (HttpURLConnection) myUrl.openConnection(); //myUrl - URL object pointing for some location 
if(connection.getResponseCode() == 200){ 
    File temp = File.createTempFile("blabla", fileName); //fileName - string name of file 
    FileOutputStream out = new FileOutputStream(temp); 
    int fileSize = Integer.parseInt(connection.getHeaderField("content-length")); 
    int counter = 0; 
    DataInputStream in = new DataInputStream(connection.getInputStream()); 
    byte ch[] = new byte[1024]; 
    System.out.println(counter); 
    while((counter += in.read(ch)) > 0){ 
     out.write(ch); 
     if(counter == fileSize){ 
      out.close(); 
      break; 
     } 
    } 
} 

локально с локального веб-сервера (локальный) это работает в совершенстве.

Но. Затем myUrl является URL-адресом файла на каком-то удаленном веб-сервере - он возвращает неожиданные результаты. Например, из источников данных файлов кажется, что он повторяет некоторые пакеты (я думаю, из-за коррупции предыдущих или someting), и полученный файл обычно примерно на 10% больше, чем оригинальный, из-за этого повторяется. Таким образом, файл поврежден и не может быть правильно открыт при просмотре изображений.

Как я могу это решить?

ответ

4

read не обязательно считывает весь буфер (особенно если он находится в конце потока).

Так изменить цикл:

for (;;) { 
    int len = in.read(ch); 
    if (len == -1) { 
     break; 
    } 
    out.write(ch, 0, len); 
} 

Возможно поместить этот код в метод где-то.

Также обратите внимание:

  • Там нет смысла использовать DataInputStream здесь (хотя readFully часто бывает полезно).
  • Всегда рядом ресурс (например, потоки) с обычным идиомы:

    final Resource resource = acquire(); 
    try { 
        use(resource); 
    } finally { 
        resource.close(); 
    } 
    
  • Вероятно, не имеет большого значения, но размер буфера 1024 немного мала. Я имею тенденцию по умолчанию 8192 произвольно.

+0

Только для завершения, большинство Java-программисты предпочитают более короткий вариант: \t INT Len; \t while ((len = in.read (ch))> = 0) { out.write (ch, 0, len); \t} Сохраняет одно условие, прерывает и повторно использует переменную в стеке, что делает ее менее подверженной ошибкам. –

+0

A предпочитают избегать побочных эффектов. Повторное использование переменных не рекомендуется! –