Как записать ответы на несколько асинхронных запросов get в один файл в асинхронном httpclient java 11?

#java #httpclient #java-11 #asynchttpclient #sendasync

#java #httpclient #java-11 #asynchttpclient #sendasync

Вопрос:

Я могу загрузить один медиафайл с помощью httpclient в java 11 следующим образом

 public class Httptest {
    
    private static HttpClient client = HttpClient.newBuilder().build();
            
    public static void main(String[] args) throws Exception {
        File fts = new File("P:/sample.ts");  //Destination of downloaded file
        fts.createNewFile();
        URI url = new URI("File url here"); //File Url
        
        HttpRequest request = HttpRequest.newBuilder()   //Creating HttpRequest using Builder class
                .GET()
                .uri(url)
                .build();
        Path file = Path.of("P:/samp.ts");
        //BodyHandlers class has methods to handle the response body
        // In this case, save it as a file (BodyHandlers.ofFile())
        HttpResponse<Path> response = client.send(request,BodyHandlers.ofFile(file)); 
    }
}

  

Приведенный выше фрагмент кода загружает файл .ts с URL-адреса. И он загружен правильно.

Теперь у меня есть список URL-адресов, List<URI> urls . Я выполнил асинхронный вызов списка URL-адресов, а также обеспечил одновременные вызовы, добавив Executor service . Я застрял в том, как записать список ответов в один файл.

Код, который я написал до сих пор:

 public class httptest{
    
   // Concurrent requests are made in 4 threads
   private static ExecutorService executorService = Executors.newFixedThreadPool(4); 

   //HttpClient built along with executorservice
   private static HttpClient client = HttpClient.newBuilder() 
            .executor(executorService)
            .build();
    
   public static void main(String[] args) throws Exception{
        File fts = new File("P:/Spyder_directory/sample.ts");
        fts.createNewFile();
        List<URI> urls = Arrays.asList(
                         new URI("Url of file 1"),
                         new URI("Url of file 2"),
                         new URI("Url of file 3"),
                         new URI("Url of file 4"),
                         new URI("Url of file 5"));
        
        
        List<HttpRequest> requests = urls.stream()
                .map(HttpRequest::newBuilder)
                .map(requestBuilder -> requestBuilder.build())
                .collect(toList());
        Path file = Path.of("P:/Spyder_directory/sample.ts");
        List<CompletableFuture<HttpResponse<Path>>> results = requests.stream()
                .map(individual_req -> client.sendAsync(individual_req,BodyHandlers.ofFile(file)))
                .collect(Collectors.toList());
   }
}
  

Файл sample.ts , созданный в конце выполнения, не содержит ответа на сделанные запросы.
Если вы поняли суть моей проблемы, кто-нибудь может предложить альтернативные решения этой проблемы.

Ответ №1:

Одной из возможностей было бы использовать HttpResponse .BodyHandlers.ofByteArrayConsumer с помощью a Consumer<Optional<byte[]>> , который записывает байты в файл. Это позволит вам контролировать, как открывается файл, позволяя добавлять к существующему файлу, а не создавать каждый раз новый файл.

Обратите внимание, что если вы это сделаете, вам не следует использовать sendAsync , потому что запросы будут отправляться одновременно, и поэтому ответ тоже будет получен одновременно. Если вы все еще хотите отправлять запросы одновременно, вам нужно будет буферизировать ответы и наложить некоторую синхронизацию при их записи в файл.

Комментарии:

1. ДА. Спасибо за ответ, я допускал небольшие ошибки, когда речь шла об асинхронном и параллельном. Consumer исправлено.