Мне нужно указать способ загрузки больших файлов.
Моя реализация работает, но может не работать с OutOfMemoryError
на стороне клиента - иногда настройка большего количества кучи помогает, иногда нет.
Я отлично работаю на своей машине (32 ГБ ОЗУ), но часто происходит сбой на машинах с ~ 6 ГБ.
Мои файлы близки к 2 ГБ.
Что следует изменить, чтобы обеспечить безопасный метод загрузки?
Я предполагаю, что ошибка происходит на entity.writeTo(...);
.
Я также думаю, что он хранит весь файл в памяти, чего не следует. Как записать все данные на диск и убедиться, что нет больших буферов памяти?
Поможет ли мне чтение из InputStream
кусками byte[1024]
?
Тот же вопрос относится к серверу. Я использую Files.copy(...)
для передачи данных, потому что я где-то читал, что он вызывает функцию API операционной системы и происходит фактический дисковый ввод-вывод.
Клиент:
public boolean requestUpdateDownload(String filePath)
{
Path path = Paths.get(filePath).toAbsolutePath();
File file = path.toFile();
String url = "http://" + host + ":" + port + "/download";
System.out.println("Downloading update file from " + url);
try
{
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet(url);
CloseableHttpResponse response = httpClient.execute(httpGet);
try
{
System.out.println(response.getStatusLine());
HttpEntity entity = response.getEntity();
long expectedSize = entity.getContentLength();
if (entity != null)
{
try (FileOutputStream fileOutputStream = new FileOutputStream(file))
{
entity.writeTo(fileOutputStream);
}
}
EntityUtils.consume(entity);
long realSize = file.length();
if (expectedSize == realSize)
{
System.out.println("Received update file: " + realSize + " bytes total.");
}
else
{
System.err.println("Update file incomplete.");
deleteFile(path);
}
}
finally
{
response.close();
}
System.out.println("Saving update file to \"" + path + "\"");
System.out.println("Update file saved.");
}
catch (Exception ex)
{
System.err.println("Unable to download update file.");
ex.printStackTrace();
deleteFile(path);
return false;
}
return true;
}
Сервер:
@Override
public void handle(HttpExchange httpExchange) throws IOException
{
System.out.println(LocalDateTime.now() + " Received file download request.");
String requestMethod = httpExchange.getRequestMethod();
if (requestMethod.equalsIgnoreCase("GET"))
{
Path path = Paths.get("ism","download", FILENAME);
if (Files.exists(path))
{
long size = Files.size(path);
Headers responseHeaders = httpExchange.getResponseHeaders();
responseHeaders.set("Content-Type", "application/x-7z-compressed");
responseHeaders.set("Content-Length", "" + size);
responseHeaders.set("Content-Disposition", "inline; filename=\""+ FILENAME + "\"");
httpExchange.sendResponseHeaders(200, size);
OutputStream outputStream = httpExchange.getResponseBody();
Files.copy(path, outputStream);
outputStream.close();
System.out.println(LocalDateTime.now() + " File downloaded - " + size + " bytes total.");
}
else
{
System.out.println(LocalDateTime.now() + " File does not exist.");
httpExchange.sendResponseHeaders(404, 0);
httpExchange.getResponseBody().close();
}
}
else
{
System.out.println(LocalDateTime.now() + " Method not supported.");
Headers responseHeaders = httpExchange.getResponseHeaders();
httpExchange.sendResponseHeaders(405, 0);
httpExchange.getResponseBody().close();
}
}