2015-06-29 18 views
5

के साथ एक फ़ाइल डाउनलोड और लिखें मैं रेट्रोफिट के साथ एक पीडीएफ फ़ाइल डाउनलोड कर रहा हूं, जिस तरह से मैं इसे डाउनलोड कर रहा हूं, वह ब्लॉक है। मैं बाइट्स की एक श्रृंखला प्राप्त करने के लिए Content-Range शीर्षलेख का उपयोग करता हूं, फिर मुझे इन बाइट्स को file पर लिखने की आवश्यकता है, समस्या उन्हें लिखने का आदेश है। मैं flatMap() फ़ंक्शन का उपयोग कर रहा हूं ताकि फ़ाइल डाउनलोड करने के लिए प्रत्येक अनुरोध के लिए एक अवलोकन योग्य हो सके।रेट्रोफिट और आरएक्सजेवा

.flatMap(new Func1<Integer, Observable<Response>>() { 
       @Override 
       public Observable<Response> call(Integer offset) { 
        int end; 

        if (offset + BLOCK_SIZE > (contentLength - 1)) 
         end = (int) contentLength - 1 - offset; 

        else 
         end = offset + BLOCK_SIZE; 

        String range = getResources().getString(R.string.range_format, offset, end); 

        return ApiAdapter.getApiService().downloadPDFBlock(range); 
       } 
      }) 

downloadPDFBlock एक तार है कि एक शीर्ष लेख के लिए आवश्यक है प्राप्त करते हैं: Range: bytes=0-3999। तो फिर मैं समारोह सदस्यता ले बाइट्स लिखने के लिए इस्तेमाल डाउनलोड किया

subscribe(new Subscriber<Response>() { 
       @Override 
       public void onCompleted() { 
        Log.i(LOG_TAG, file.getAbsolutePath()); 
       } 

       @Override 
       public void onError(Throwable e) { 
        e.printStackTrace(); 
       } 

       @Override 
       public void onNext(Response response) { 
        writeInCache(response); 
        } 
       } 
      }); 

लेकिन समस्या यह है कि लेखन की प्रक्रिया अव्यवस्थित बना है। उदाहरण के लिए: यदि Range: bytes=44959-53151 पहले डाउनलोड किया गया है, तो यह बाइट होगा जो फ़ाइल में पहले लिखा जाएगा। मैंने BlockingObserver पढ़ा है लेकिन मुझे नहीं पता कि यह समाधान हो सकता है या नहीं।

मुझे आशा है कि आप मेरी मदद कर सकते हैं।

+1

चेक 'concatMap' ऑपरेटर http://fernandocejas.com/2015/01/11/rxjava-observable-tranformation-concatmap-vs-flatmap/ –

+1

वैकल्पिक रूप से, एक RandomAccessFile का उपयोग करें और ऑफसेट एक ही फाइल में लिखने अनुरोध के लिए बनाया गया था। – akarnokd

+0

आपको बड़ी सामग्री लोड करने के लिए DownloadManager का उपयोग करना चाहिए। http://developer.android.com/reference/android/app/DownloadManager.html –

उत्तर

8

फ़ाइल डाउनलोड करने और एंड्रॉइड में डिस्क पर सहेजने के लिए यहां एक अच्छा example है।

लैम्बडा अभिव्यक्ति का उपयोग किये बिना उपर्युक्त लिंक का एक संशोधन यहां दिया गया है।

रेट्रोफिट 2 इंटरफ़ेस, @ बड़ी फ़ाइलों को डाउनलोड करने के लिए @ स्ट्रीमिंग।

public interface RetrofitApi { 
    @Streaming 
    @GET 
    Observable<Response<ResponseBody>> downloadFile(@Url String fileUrl); 
} 

फ़ाइल डाउनलोड करने और रेट्रोफिट 2 और आरएक्सजेवा का उपयोग करके डिस्क पर सहेजने के लिए कोड। नीचे दिए गए कोड में बेस यूआरएल और यूआरएल पथ को उस फ़ाइल के वास्तविक यूआरएल पर अपडेट करें जिसे आपको डाउनलोड करने की आवश्यकता है।

public void downloadZipFile() { 
    Retrofit retrofit = new Retrofit.Builder() 
      .baseUrl("https://my.resources.com/") 
      .client(new OkHttpClient.Builder().build()) 
      .addCallAdapterFactory(RxJavaCallAdapterFactory.create()).build(); 
    RetrofitApi downloadService = retrofit.create(RetrofitApi.class); 

    downloadService.downloadFile("resources/archive/important_files.zip") 
      .flatMap(new Func1<Response<ResponseBody>, Observable<File>>() { 
       @Override 
       public Observable<File> call(final Response<ResponseBody> responseBodyResponse) { 
        return Observable.create(new Observable.OnSubscribe<File>() { 
         @Override 
         public void call(Subscriber<? super File> subscriber) { 
          try { 
           // you can access headers of response 
           String header = responseBodyResponse.headers().get("Content-Disposition"); 
           // this is specific case, it's up to you how you want to save your file 
           // if you are not downloading file from direct link, you might be lucky to obtain file name from header 
           String fileName = header.replace("attachment; filename=", ""); 
           // will create file in global Music directory, can be any other directory, just don't forget to handle permissions 
           File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsoluteFile(), fileName); 

           BufferedSink sink = Okio.buffer(Okio.sink(file)); 
           // you can access body of response 
           sink.writeAll(responseBodyResponse.body().source()); 
           sink.close(); 
           subscriber.onNext(file); 
           subscriber.onCompleted(); 
          } catch (IOException e) { 
           e.printStackTrace(); 
           subscriber.onError(e); 
          } 
         } 
        }); 
       } 
      }) 
      .subscribeOn(Schedulers.io()) 
      .observeOn(AndroidSchedulers.mainThread()) 
      .subscribe(new Observer<File>() { 
          @Override 
          public void onCompleted() { 
           Log.d("downloadZipFile", "onCompleted"); 
          } 

          @Override 
          public void onError(Throwable e) { 
           e.printStackTrace(); 
           Log.d("downloadZipFile", "Error " + e.getMessage()); 
          } 

          @Override 
          public void onNext(File file) { 
           Log.d("downloadZipFile", "File downloaded to " + file.getAbsolutePath()); 
          } 
         }); 
} 
+0

हे मैन, आप प्रत्येक बार जब आप फ़ाइल डाउनलोड करते हैं तो सर्वर एपीआई इंस्टेंस बना रहे हैं –

+2

यह प्रदर्शन के लिए है, रेट्रोफिट इंस्टेंस को वैश्विक स्थिति में ले जाया जा सकता है। –

+0

आपने पैरामीटर '@ यूआरएल स्ट्रिंग फ़ाइल यूआरएल' के रूप में पेस्ट किया है लेकिन पथ 'संसाधन/संग्रह/important_files.zip "दर्ज करें ... लगता है कि विधि @ @ स्ट्रीमिंग @GET ({path}) हो सकती है अवलोकन <प्रतिक्रिया <प्रतिक्रिया बॉडी >> डाउनलोडफाइल (@ पैथ ("पथ") स्ट्रिंग फ़ाइल यूआरएल); ' – NickUnuchek

संबंधित मुद्दे