java 如何使用 Retrofit2 下载文件?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34156530/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 22:32:30  来源:igfitidea点击:

How to download a file with Retrofit2?

javaphpandroiddownloadretrofit

提问by Mohammed Aouf Zouag

How can I downloada file(image/video)from my PHPserver using Retrofit2?

我怎样才能下载一个文件(图像/视频)从我的PHP服务器使用Retrofit2

I wasn't able to find any resources or tutorials online on how to proceed; I found this postthat treats a certain download error on SObut it's not very clear to me. Could anyone point me to the right direction?

我无法在网上找到有关如何进行的任何资源或教程;我发现这篇文章处理了SO上的某个下载错误,但对我来说不是很清楚。有人能指出我正确的方向吗?

UPDATE:

更新:

Here is my code:

这是我的代码:

FileDownloadService.java

文件下载服务.java

public interface FileDownloadService {
    @GET(Constants.UPLOADS_DIRECTORY + "/{filename}")
    @Streaming
    Call<ResponseBody> downloadRetrofit(@Path("filename") String fileName);
}

MainActivity.java(@Blackbelt's solution)

MainActivity.java@Blackbelt的解决方案)

private void downloadFile(String filename) {
    FileDownloadService service = ServiceGenerator
            .createService(FileDownloadService.class, Constants.SERVER_IP_ADDRESS);
    Call<ResponseBody> call = service.downloadRetrofit("db90408a4bb1ee65d3e09d261494a49f.jpg");

    call.enqueue(new Callback<ResponseBody>() {
        @Override
        public void onResponse(final Response<ResponseBody> response, Retrofit retrofit) {
            try {
                InputStream is = response.body().byteStream();
                FileOutputStream fos = new FileOutputStream(
                        new File(Environment.getExternalStorageDirectory(), "image.jpg")
                );
                int read = 0;
                byte[] buffer = new byte[32768];
                while ((read = is.read(buffer)) > 0) {
                    fos.write(buffer, 0, read);
                }

                fos.close();
                is.close();
            } catch (Exception e) {
                Toast.makeText(MainActivity.this, "Exception: " + e.toString(), Toast.LENGTH_LONG).show();
            }
        }

        @Override
        public void onFailure(Throwable t) {
            Toast.makeText(MainActivity.this, "Failed to download file...", Toast.LENGTH_LONG).show();
        }
    });
}

I get a FileNotFoundExceptionwhen USB debugging is active, & a NetworkOnMainThreadExceptionwhen not.

当 USB 调试处于活动状态时,我会收到FileNotFoundException 异常,否则会收到NetworkOnMainThreadException

MainActivity.java:(@Emanuel's solution)

MainActivity.java: @Emanuel的溶液)

private void downloadFile(String filename) {
    FileDownloadService service = ServiceGenerator
            .createService(FileDownloadService.class, Constants.SERVER_IP_ADDRESS);
    Call<ResponseBody> call = service.downloadRetrofit("db90408a4bb1ee65d3e09d261494a49f.jpg");

    call.enqueue(new Callback<ResponseBody>() {
        @Override
        public void onResponse(final Response<ResponseBody> response, Retrofit retrofit) {
            Log.i(TAG, "external storage = " + (Environment.getExternalStorageState() == null));
            Toast.makeText(MainActivity.this, "Downloading file... " + Environment.getExternalStorageDirectory(), Toast.LENGTH_LONG).show();

            File file = new File(Environment.getDataDirectory().toString() + "/aouf/image.jpg");
            try {
                file.createNewFile();
                Files.asByteSink(file).write(response.body().bytes());
            } catch (Exception e) {
                Toast.makeText(MainActivity.this,
                        "Exception: " + e.toString(),
                        Toast.LENGTH_LONG).show();
            }
        }

        @Override
        public void onFailure(Throwable t) {
            Toast.makeText(MainActivity.this, "Failed to download file...", Toast.LENGTH_LONG).show();
        }
    });
}

I get a FileNotFoundException.

我得到一个FileNotFoundException

采纳答案by Emanuel Seidinger

This is a little example showing how to download the Retrofit JAR file. You can adapt it to your needs.

这是一个显示如何下载 Retrofit JAR 文件的小示例。您可以根据自己的需要进行调整。

This is the interface:

这是界面:

import com.squareup.okhttp.ResponseBody;
import retrofit.Call;
import retrofit.http.GET;
import retrofit.http.Path;

interface RetrofitDownload {
    @GET("/maven2/com/squareup/retrofit/retrofit/2.0.0-beta2/{fileName}")
    Call<ResponseBody> downloadRetrofit(@Path("fileName") String fileName);
}

And this is a Java class using the interface:

这是一个使用接口的 Java 类:

import com.google.common.io.Files;
import com.squareup.okhttp.ResponseBody;
import retrofit.Call;
import retrofit.Callback;
import retrofit.Response;
import retrofit.Retrofit;

import java.io.File;
import java.io.IOException;

public class Main {

    public static void main(String... args) {
        Retrofit retrofit = new Retrofit.Builder().
                baseUrl("http://repo1.maven.org").
                build();

        RetrofitDownload retrofitDownload = retrofit.create(RetrofitDownload.class);

        Call<ResponseBody> call = retrofitDownload.downloadRetrofit("retrofit-2.0.0-beta2.jar");

        call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Response<ResponseBody> response, Retrofit retrofitParam) {
                File file = new File("retrofit-2.0.0-beta2.jar");
                try {
                    file.createNewFile();
                    Files.asByteSink(file).write(response.body().bytes());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onFailure(Throwable t) {
            }
        });
    }
}

回答by Ivan Milisavljevic

If anybody stumbles upon this response this is how i did it using retrofit in conjunction with Rx. Every downloaded file is cached, and any subsequent requests with the same url will return the already downloaded file.

如果有人偶然发现此响应,这就是我将改造与 Rx 结合使用的方式。每个下载的文件都会被缓存,任何具有相同 url 的后续请求都将返回已下载的文件。

In order to use this just subscribe to this observable and pass your url. This will save your file in downloads directory so make sure to ask for permissions if your app targets API 23 or greater.

为了使用它,只需订阅这个 observable 并传递你的 url。这会将您的文件保存在下载目录中,因此如果您的应用面向 API 23 或更高版本,请确保请求权限。

  public Observable<File> getFile(final String filepath) {
    URL url = null;
    try {
        url = new URL(filepath);
    } catch (MalformedURLException e) {
        e.printStackTrace();
    }
    final String name = url.getPath().substring(url.getPath().lastIndexOf("/") + 1);
    final File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), name);
    if (file.exists()) {
        return Observable.just(file);
    } else {
        return mRemoteService.getFile(filepath).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 {

                            final File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsoluteFile(), name);

                            BufferedSink sink = Okio.buffer(Okio.sink(file));
                            sink.writeAll(responseBodyResponse.body().source());
                            sink.flush();
                            sink.close();
                            subscriber.onNext(file);
                            subscriber.onCompleted();
                            file.deleteOnExit();
                        } catch (IOException e) {
                            Timber.e("Save pdf failed with error %s", e.getMessage());
                            subscriber.onError(e);
                        }
                    }
                });
            }
        });
    }
}

Retrofit part of the call

改造部分通话

@Streaming
@GET
Observable<retrofit2.Response<ResponseBody>> getFile(@Url String fileUrl);

回答by Blackbelt

to downloada file, you might want the raw InputStreamof the response and write is content on the sdcard. To do so, you should use ResponseBodyas Tfor your return type, Call<ResponseBody>. You will then use Retrofitto enqueuea

下载文件,您可能需要原始InputStream响应并写入sdcard. 为此,您应该使用ResponseBody作为T您的返回类型,Call<ResponseBody>. 然后,您将使用Retrofitenqueue一个

Callback<ResponseBody>

and when the onResponse

onResponse

@Override
public void onResponse(final Response<ResponseBody> response, Retrofit retrofit) {

is invoked, you can retrieve the InputStream, with response.byteStream(), read from it, and write what you read on the sdcard (have a look here)

被调用,您可以检索InputStream, with response.byteStream(),从中读取,并将您读到的内容写入 sdcard (看看这里