2017-02-20 3 views
2

У меня есть веб-сервис, способный возвращать PDF файлы двумя способами:Потребляйте JSON/Base64 закодированный файл в Android/Java

RAW: Файл просто включен в теле ответа. Например:

HTTP/1.1 200 OK 
Content-Type: application/pdf 

<file_contents> 

JSON: Файл кодируется (Base 64) и служил в качестве JSON со следующей структурой:

HTTP/1.1 200 OK 
Content-Type: application/json 

{ 
    "base64": <file_contents_base64> 
} 

Я хочу, чтобы иметь возможность потреблять как услуги по Android/Java с помощью следующей архитектуры:

// Get response body input stream (OUT OF THE SCOPE OF THIS QUESTION) 
InputStream bodyStream = getResponseBodyInputStream(); 

// Get PDF file contents input stream from body stream 
InputStream fileStream = getPDFFileContentsInputStream(bodyStream); 

// Write stream to a local file (OUT OF THE SCOPE OF THIS QUESTION) 
saveToFile(fileStream); 

в первом случае (RAW), тело ответа будет сам файл. Это означает, что реализация getPDFFileContentsInputStream(InputStream) метода тривиальна:

@NonNull InputStream getPDFFileContentsInputStream(@NonNull InputStream bodyStream) { 
    // Return the input 
    return bodyStream; 
} 

Вопрос заключается в том: , как реализовать метод getPDFFileContentsInputStream(InputStream) для второго случая (JSON ответа)?

+0

'byte [] encodedBytes = json.getBytes (" base64 "); byte [] decodedBytes = (новый BASE64Decoder()). decodeBuffer (encodedBytes); вернуть новый ByteArrayInputStream (decodedBytes); ' – AnixPasBesoin

+0

проверить мой (отредактированный) комментарий в моем ответе. – ram

ответ

1

Вы можете использовать любой json-парсер (например, Jackson или Gson), а затем использовать Base64InputStream из кодека apache-commons.

EDIT: Вы можете получить входной поток из строки с использованием ByteArrayInputStream, т.е.

InputStream stream = new ByteArrayInputStream(exampleString.getBytes(StandardCharsets.UTF_8)); 

как указано here.

EDIT 2: Это вызовет 2-х прохождение данных, и если файл большой, могут возникнуть проблемы с памятью. Чтобы решить эту проблему, вы можете использовать Джексон и самостоятельно проанализировать содержимое, например, this вместо того, чтобы получить весь объект через отражение. вы можете обернуть исходный поток ввода в другой, скажем ExtractingInputStream, и это пропустит данные в базовом потоке ввода до кодированной части. Затем вы можете обернуть этот экземпляр ExtractingInputStream в Base64InputStream. Простой алгоритм пропустить ненужные части будет таким: В конструкторе ExtractingInputStream пропустите, пока вы не прочитаете три кавычки. В методе чтения возвращайте возвращаемый поток, за исключением возвращаемого -1, если базовый поток возвращает кавычку, которая соответствует концу кодированных базовых 64 данных.

+0

Прохладный! Но как я могу получить «InputStream», который испускает значение «base64» из JSON, поэтому я могу обернуть его в «Base64InputStream»? –

+0

Спасибо за редактирование ответа. Дело в том, что я не разбираюсь в потоке JSON, получая значение * base64 * как объект (String). Файлы PDF могут быть большими (+ 10 МБ без кодировки base64), которые потенциально могут потреблять больше памяти, чем могут предложить устройства. Из того, что я знаю, ни у JsonReader (Gson), ни у JsonParser (Jackson) есть способ получить значение как 'InputStream', а не' String' –

+0

Вы проверили пример в edit 2?В классе JsonParser 'Jackson' есть метод, называемый' getInputSource', который является «методом, который может быть использован для получения доступа к объекту, который используется для доступа к обрабатываемому элементу ввода: обычно это либо InputStream, либо Reader, в зависимости от того, что синтаксический анализатор был построен с ", согласно их [doc] (http://fasterxml.github.io/jackson-core/javadoc/2.1.0/com/fasterxml/jackson/core/JsonParser.html). Если у вас есть дополнительная помощь, мне может понадобиться полностью написать этот метод. Попробуй, если не можешь, я помогу. – ram

Смежные вопросы