Загрузка / выгрузка больших файлов Java через HTTP - OutOfMemoryError на стороне клиента? - PullRequest
0 голосов
/ 14 января 2019

Мне нужно указать способ загрузки больших файлов.

Моя реализация работает, но может не работать с 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();
    }
}
...