我正在下载一个改装的pdf文件,我下载它的方式是块.我使用Content-Range标头获取一个字节范围,然后我需要在文件上写这些字节,问题是编写它们的顺序.我正在使用flatMap()函数为每个下载文件必须完成的请求返回一个observable.
.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函数写下载的字节
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但我不知道这是否可以解决问题.
我希望你能帮助我.
解决方法
这是一个很好的
example用于下载文件并将其保存到Android中的磁盘.
Retrofit 2界面,@ Streaming用于下载大文件.
public interface RetrofitApi { @Streaming @GET Observable<Response<ResponseBody>> downloadFile(@Url String fileUrl); }
使用Retrofit 2和rxjava下载文件并将其保存到磁盘的代码.将下面代码中的baseUrl和url路径更新为您需要下载的文件的实际URL.
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()); } }); }