2009-02-23 4 views
68

У меня проблемы с загрузкой бинарного файла (видео) в моем приложении из Интернета. В Quicktime, если я загружаю его напрямую, он отлично работает, но через мое приложение каким-то образом его перепутали (хотя они выглядят точно так же в текстовом редакторе). Вот пример:Android скачать проблемы с двоичным файлом

URL u = new URL("http://www.path.to/a.mp4?video"); 
    HttpURLConnection c = (HttpURLConnection) u.openConnection(); 
    c.setRequestMethod("GET"); 
    c.setDoOutput(true); 
    c.connect(); 
    FileOutputStream f = new FileOutputStream(new File(root,"Video.mp4")); 


    InputStream in = c.getInputStream(); 

    byte[] buffer = new byte[1024]; 
    int len1 = 0; 
    while ((len1 = in.read(buffer)) > 0) { 
     f.write(buffer); 
    } 
    f.close(); 

ответ

91

Я не знаю, если это единственная проблема, но у вас есть классический Java глюк там: Вы не рассчитываете на то, что читать() является всегда разрешено вернуть меньше байтов, чем вы просите. Таким образом, ваше чтение может получить меньше 1024 байт, но ваша запись всегда выдает ровно 1024 байта, включая байты из предыдущей итерации цикла.

Correct с:

while ((len1 = in.read(buffer)) > 0) { 
     f.write(buffer,0, len1); 
} 

Возможно выше сети латентность или меньшие размеры пакетов из 3G на Android усугубляют эффект?

+4

Какая глупая ошибка ... спасибо! Это то, что происходит, когда вы не читаете учебник правильно :) –

+3

Спасибо ... тоже помог мне. –

+0

Как насчет инициализации буфера? Как насчет защиты от исключения? Как насчет освобождения ресурсов? Я думаю, что это хороший, но не полный ответ. Здесь есть еще более полные ответы. –

16

Одна из проблем заключается в том, что вы читаете буфер. Если каждое чтение входного потока не является точным кратным 1024, вы скопируете плохие данные. Использование:

byte[] buffer = new byte[1024]; 
int len1 = 0; 
while ((len1 = in.read(buffer)) != -1) { 
    f.write(buffer,0, len1); 
} 
+0

В строке 4, вы имеете в виду len1, не LEN? –

+0

Я смотрю на пример Ry4an и предполагаю, что вы имеете в виду len1 - спасибо. –

14
public class download extends Activity { 

    private static String fileName = "file.3gp"; 
    private static final String MY_URL = "Your download url goes here"; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 

     try { 
      URL url = new URL(MY_URL); 
      HttpURLConnection c = (HttpURLConnection) url.openConnection(); 
      c.setRequestMethod("GET"); 
      c.setDoOutput(true); 
      c.connect(); 

      String PATH = Environment.getExternalStorageDirectory() 
       + "/download/"; 
      Log.d("Abhan", "PATH: " + PATH); 
      File file = new File(PATH); 
      if(!file.exists()) { 
       file.mkdirs(); 
      } 
      File outputFile = new File(file, fileName); 
      FileOutputStream fos = new FileOutputStream(outputFile); 
      InputStream is = c.getInputStream(); 
      byte[] buffer = new byte[1024]; 
      int len1 = 0; 
      while ((len1 = is.read(buffer)) != -1) { 
       fos.write(buffer, 0, len1); 
      } 
      fos.flush(); 
      fos.close(); 
      is.close(); 
     } catch (IOException e) { 
      Log.e("Abhan", "Error: " + e); 
     } 
     Log.i("Abhan", "Check Your File."); 
    } 
} 
+0

Этот ответ не сработает. Сетевые подключения в основном потоке будут вызывать 'android.os.NetworkOnMainThreadException'. – JBirdVegas

+0

@JBirdVegas Не запускайте работу, связанную с сетью, в основном потоке. Пожалуйста, создайте рабочий поток. – 2015-05-31 11:33:01

+0

Используйте AsyncTask doInBackground, чтобы выполнить код try {} catch. и удалите из него setDoOutput (true). – Nepster

2

Просто используйте метод копирования apache (Apache Commons IO) - преимущество использования Java!

IOUtils.copy(is, os); 

Не забудьте закрыть потоки в блоке, наконец:

try{ 
     ... 
} finally { 
    IOUtils.closeQuietly(is); 
    IOUtils.closeQuietly(os); 
} 
+2

И не пересекайте потоки. –

+2

Библиотека 200k просто для скачивания файла ..... –

4

Я установил код, основанный на предыдущем обратных по этой теме. Я тестировал, используя eclipse и несколько больших файлов. Он работает нормально. Просто скопируйте и вставьте это в свою среду и измените http-путь и местоположение, в которое вы хотите загрузить файл.

try { 
    //this is the file you want to download from the remote server 
    String path ="http://localhost:8080/somefile.zip"; 
    //this is the name of the local file you will create 
    String targetFileName 
     boolean eof = false; 
    URL u = new URL(path); 
    HttpURLConnection c = (HttpURLConnection) u.openConnection(); 
    c.setRequestMethod("GET"); 
    c.setDoOutput(true); 
    c.connect(); 
    FileOutputStream f = new FileOutputStream(new File("c:\\junk\\"+targetFileName)); 
     InputStream in = c.getInputStream(); 
     byte[] buffer = new byte[1024]; 
     int len1 = 0; 
     while ((len1 = in.read(buffer)) > 0) { 
     f.write(buffer,0, len1); 
       } 
    f.close(); 
    } catch (MalformedURLException e) { 
    // TODO Auto-generated catch block 
    e.printStackTrace(); 
    } catch (ProtocolException e) { 
    // TODO Auto-generated catch block 
    e.printStackTrace(); 
    } catch (FileNotFoundException e) { 
    // TODO Auto-generated catch block 
    e.printStackTrace(); 
    } catch (IOException e) { 
    // TODO Auto-generated catch block 
    e.printStackTrace(); 
} 

Успехов Реза Aghamohammadi

+0

таким образом будет загружен тот же файл. я имею в виду, если файл уже загружен, он даст предупреждение? – Loshi

+0

удалить setDoOutput (true); от кода – Nepster

28
new DefaultHttpClient().execute(new HttpGet("http://www.path.to/a.mp4?video")) 
     .getEntity().writeTo(
       new FileOutputStream(new File(root,"Video.mp4"))); 
+3

one line решение. Nice – Santhosh

+1

Мне нравится однострочное решение. Тем не менее, вы должны проверить объект перед записью в файл, иначе файл будет создан, даже если есть проблема с загрузкой. Поэтому в следующий раз вы можете попытаться открыть поврежденный файл. – thanhbinh84

+0

Как я могу назвать загруженный файл так же, как и исходное имя файла динамически? –

Смежные вопросы