1. Обзор
В этом туториале будет приведен практический пример того, как скачать бинарный файл с помощью библиотеки OkHttp .
2. Зависимости Maven
Мы начнем с добавления зависимости базовой библиотеки okhttp :
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.9.1</version>
</dependency>
Затем, если мы хотим написать интеграционный тест для модуля, реализованного с помощью библиотеки OkHttp, мы можем использовать библиотеку mockwebserver . В этой библиотеке есть инструменты для имитации сервера и его ответов:
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>mockwebserver</artifactId>
<version>4.9.1</version>
<scope>test</scope>
</dependency>
3. Запрос бинарного файла
Сначала мы реализуем класс, который получает в качестве параметра URL-адрес, откуда можно загрузить файл, а также создает и выполняет HTTP-запрос для этого URL-адреса.
Чтобы сделать класс тестируемым, мы внедрим OkHttpClient и модуль записи
в конструктор:
public class BinaryFileDownloader implements AutoCloseable {
private final OkHttpClient client;
private final BinaryFileWriter writer;
public BinaryFileDownloader(OkHttpClient client, BinaryFileWriter writer) {
this.client = client;
this.writer = writer;
}
}
Далее мы реализуем метод, загружающий файл с URL-адреса :
public long download(String url) throws IOException {
Request request = new Request.Builder().url(url).build();
Response response = client.newCall(request).execute();
ResponseBody responseBody = response.body();
if (responseBody == null) {
throw new IllegalStateException("Response doesn't contain a file");
}
double length = Double.parseDouble(Objects.requireNonNull(response.header(CONTENT_LENGTH, "1")));
return writer.write(responseBody.byteStream(), length);
}
Процесс загрузки файла состоит из четырех шагов. Создайте запрос, используя URL-адрес. Выполните запрос и получите ответ. Получите тело ответа или потерпите неудачу, если оно пустое.
Запишите байты
тела ответа в файл.
4. Запись ответа в локальный файл
Чтобы записать полученные байты
из ответа в локальный файл, мы реализуем класс BinaryFileWriter
, который принимает в качестве входных данных InputStream
и OutputStream
и копирует содержимое из InputStream
в OutputStream
.
OutputStream будет внедрен в конструктор, чтобы класс можно было протестировать :
public class BinaryFileWriter implements AutoCloseable {
private final OutputStream outputStream;
public BinaryFileWriter(OutputStream outputStream) {
this.outputStream = outputStream;
}
}
Теперь мы реализуем метод, который копирует содержимое из InputStream
в OutputStream
. Метод сначала оборачивает InputStream
в BufferedInputStream
, чтобы мы могли считывать больше байтов
за раз. Затем мы готовим буфер данных, в котором мы временно храним байты
из InputStream
.
Наконец, мы запишем
буферизованные данные в OutputStream
. Мы делаем это до тех пор, пока у InputStream
есть данные для чтения:
public long write(InputStream inputStream) throws IOException {
try (BufferedInputStream input = new BufferedInputStream(inputStream)) {
byte[] dataBuffer = new byte[CHUNK_SIZE];
int readBytes;
long totalBytes = 0;
while ((readBytes = input.read(dataBuffer)) != -1) {
totalBytes += readBytes;
outputStream.write(dataBuffer, 0, readBytes);
}
return totalBytes;
}
}
5. Получение прогресса загрузки файла
В некоторых случаях мы можем захотеть сообщить пользователю о ходе загрузки файла.
Сначала нам нужно создать функциональный интерфейс :
public interface ProgressCallback {
void onProgress(double progress);
}
Затем мы будем использовать его в классе BinaryFileWriter
. Это даст нам на каждом шагу общее количество байтов
, которые загрузчик уже записал.
Во- первых, мы добавим ProgressCallback
в качестве поля в класс записи . Затем мы обновим метод записи
, чтобы получить в качестве параметра длину
ответа . Это поможет нам рассчитать прогресс.
Затем мы вызовем метод onProgress
с вычисленным прогрессом из общего количества
записанных байтов и длины:
public class BinaryFileWriter implements AutoCloseable {
private final ProgressCallback progressCallback;
public long write(InputStream inputStream, double length) {
//...
progressCallback.onProgress(totalBytes / length * 100.0);
}
}
Наконец, мы обновим класс BinaryFileDownloader
, чтобы он вызывал метод записи
с общей длиной ответа . Мы получим длину ответа из заголовка Content-Length
, а затем передадим ее методу записи :
public class BinaryFileDownloader {
public long download(String url) {
double length = getResponseLength(response);
return write(responseBody, length);
}
private double getResponseLength(Response response) {
return Double.parseDouble(Objects.requireNonNull(response.header(CONTENT_LENGTH, "1")));
}
}
6. Заключение
В этой статье мы реализовали простой, но практичный пример загрузки бинарного файла с URL с помощью библиотеки OkHttp .
Для полной реализации приложения загрузки файлов, а также модульных тестов, ознакомьтесь с проектом на GitHub .