2017-01-12 3 views
3

Метод, который я написал для загрузки файлов, всегда создает поврежденные файлы.Загрузка поврежденных файлов с помощью OkHttp

public static String okDownloadToFileSync(final String link, final String fileName, final boolean temp, DownloadStatusManager statusManager, ErrorDisplayerInterface errorDisplayerInterface) { 

    Request request = new Request.Builder() 
      .url(link) 
      .build(); 


    OkHttpClient client = Api.getInstance().getOkHttpClient(); 
    OutputStream output = null; 
    InputStream input = null; 

    try { 

     Response response = client.newCall(request).execute(); 

     //Add the file length to the statusManager 
     final int contentLength = Integer.parseInt(response.header("Content-Length")); 
     if (statusManager != null) { 
      statusManager.add(Hash.md5(link), contentLength); 
     } 

     //Get content type to know extension 
     final String contentType = response.header("Content-Type"); 
     final String ext = contentTypeMap.get(contentType); 

     Log.i(TAG, link + "\n --> contentType = " + contentType + "\n --> ext = " + ext); 

     if (ext == null) { 
      Log.e(TAG, "-----------\next is null, seems like there is a problem with that url : \n   " + link + "\n----------"); 
      return null; 
     } else if (ext.equals("json")) { 
      Log.e(TAG, "-----------\ndownloadable file seems to be a json, seems like there is a problem with that url : \n   " + link + "\n----------"); 
      return null; 
     } 

     //Check if file already exists 
     if (!temp && fileName != null) { 
      File test = new File(M360Application.getContext().getFilesDir(), fileName + "." + ext); 
      if (test.exists()) { 
       Log.i(TAG, "File exists ! : " + test.getPath()); 
       test.delete(); 
       //return test.getAbsolutePath(); 
      } 
     } 

     // expect HTTP 200 OK, so we don't mistakenly save error report instead of the file 
     if (!response.isSuccessful()) { 
      errorDisplayerInterface.popWarn(null, "Error while downloading " + link, "connection.getResponseCode() != HttpURLConnection.HTTP_OK"); 
      return null; 
     } 

     input = response.body().byteStream(); 

     File file; 
     if (temp) { 
      file = File.createTempFile(UUID.randomUUID().toString(), ext, M360Application.getContext().getCacheDir()); 
     } else { 
      file = new File(M360Application.getContext().getFilesDir(), fileName + "." + ext); 
     } 


     output = new FileOutputStream(file); 

     output.write(response.body().bytes()); 

//   byte data[] = new byte[4096]; 
//   long total = 0; 
//   int count; 
//   while ((count = input.read(data)) != -1) { 
//    output.write(data, 0, count); 
//    total++; 
// 
//    if (statusManager != null) { 
//     statusManager.update(Hash.md5(link), contentLength - total); 
//    } 
//   } 

     return file.getAbsolutePath(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
     errorDisplayerInterface.popError(null, e); 

    } finally { 
     if (statusManager != null) { 
      statusManager.finish(Hash.md5(link)); 
     } 
     try { 
      if (output != null) 
       output.close(); 
      if (input != null) 
       input.close(); 
     } catch (IOException ignored) { 
      ignored.printStackTrace(); 
     } 

    } 
    return null; 
} 

я получить доступ к этим файл с помощью ADB, передать их на мой sccard, и я вижу, что они, кажется, правильный размер, но не имеет типа в соответствии, например, Linux file команды.

Знаете ли вы, чего не хватает и как его исправить?

спасибо.


Редактировать

Simpler версии коды (но ошибка такой же)

public static String okioDownloadToFileSync(final String link, final String fileName) throws IOException { 

    Request request = new Request.Builder() 
      .url(link) 
      .build(); 


    OkHttpClient client = Api.getInstance().getOkHttpClient(); 
    Response response = client.newCall(request).execute(); 

    final int contentLength = Integer.parseInt(response.header("Content-Length")); 

    //Get content type to know extension 
    final String contentType = response.header("Content-Type"); 
    final String ext = contentTypeMap.get(contentType); 

    // expect HTTP 200 OK, so we don't mistakenly save error report instead of the file 
    if (!response.isSuccessful()) { 
     return null; 
    } 

    File file = new File(M360Application.getContext().getFilesDir(), fileName + "." + ext); 

    BufferedSink sink = Okio.buffer(Okio.sink(file)); 
    sink.writeAll(response.body().source()); 
    sink.close(); 

    Log.i(TAG, "file.length : " + file.length() + " | contentLength : " + contentLength); 

    return file.getAbsolutePath(); 

} 

Журнал: file.length : 2485394 | contentLength : 1399242


Решение

Проблема заключалась в том, что я получал OkHttpClient от моего синглтона API, который использовался в модификации и имел перехватчики с множественным числом. Эти перехватчики загрязняли реакцию.

Итак, я OkHttpClient client = Api.getInstance().getOkHttpClient(); стал OkHttpClient client = new OkHttpClient.Builder().build();, и все в порядке!

Большое спасибо. Сейчас я деля метод на более мелкие куски.

+0

Так как намек: от «чистого качества кода» точки зрения ... Вы можете сделать много вещей, чтобы улучшить этот код; начиная с удаления отходов (например, прокомментированного кода) и уделения большего внимания правилу «одного слоя абстракции» - вы просто делаете слишком много вещей в этом одном плохом методе. Наконец: прочитайте о try-with-resources. Это спасет вас от окончательной проверки. – GhostCat

+1

'они, похоже, имеют правильный размер'. Казаться? Разве вы даже не знаете, равен ли размер? К последнему байту? – greenapps

+0

Здравствуйте, спасибо за отзыв! Прокомментированный код там, чтобы показать вам, что там я попытался умножить способ подачи файла. Что касается правила одиночной абстракции, что бы вы посоветовали двигаться? Я чувствую, что единственное, что делает этот метод, это загрузка файла, я не вижу, что я могу извлечь. Никогда не слышал о пробных ресурсах, я читаю это немедленно. @greenapps Как я написал, я понял, что я только проверял размер КБ, а не так, как вы заявили его «до последнего байта», в настоящее время я исправляю этот факт. –

ответ

0

Вместо output.write(response.body().bytes()); попробовать что-то вроде этого

byte[] buff = new byte[1024 * 4]; 

while (true) { 
    int byteCount = input.read(buff); 
    if (byteCount == -1) { 
     break; 
    } 
    output.write(buff, 0, byteCount); 
} 
+0

Он очень похож на прокомментированную часть (только под 'output.write (response.body(). Bytes ());), которые я пробовал раньше. У меня больше не было успеха –

+0

Что говорит ваш журнал? Возможно, у вас есть проблемы с типом контента и расширением? – Chupik

+0

Расширение в порядке, файл имеет неправильный размер: 'Log.i (TAG," file.length: "+ file.length() +" | contentLength: "+ contentLength);' => 'file.length : 2485394 | contentLength: 1399242' –

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