Потоковая загрузка образа base64 с использованием дооснащения

У меня есть вышестоящий сервер, который принимает отправку изображений с помощью rest. Отправленное изображение является частью полезной нагрузки JSON, аналогичной этому.

{
  "name": "Blah.jpg",
  "uploader": "user1",
  "image": "<base64.....>"
}

Использование этой стратегии работает для небольших изображений, но приводит к ошибкам «Недостаточно памяти» для изображений большего размера.

Можно ли транслировать компонент изображения base64? Передать что-то вроде итератора, который будет использоваться для чтения фрагментов изображения, их base64 и отправки их непосредственно в сеть?


person Lmwangi    schedule 20.06.2017    source источник
comment
Можно ли загружать файлы напрямую, POST не упаковывая большие двоичные объекты в полезные данные JSON?   -  person Lyubomyr Shaydariv    schedule 20.06.2017
comment
Подумайте об использовании tus для отправки изображения, он предназначен для этого и позволяет возобновлять прерванные передачи. Ваше текущее решение на самом деле наихудшее из возможных, обратите внимание, что строка base64 примерно в 1,5 раза больше, чем ваше исходное изображение. Вы должны загрузить изображение с помощью tus и указать идентификатор загрузки tus в своем json   -  person user1209216    schedule 20.06.2017
comment
Спасибо за комментарии. Мы думаем попросить наш апстрим переработать API и позволить нам публиковать сообщения напрямую, как говорит @LyubomyrShaydariv. Причина для встроенного образа base64 заключалась в том, чтобы сделать один HTTP-вызов для передачи изображения и метаданных изображения. Вероятно, нам придется сделать 2 вызова в новом API.   -  person Lmwangi    schedule 20.06.2017
comment
Внимание! Я отредактировал принятый ответ, указав, что мне больше всего понравилось. В последний момент я столкнулся с некоторыми проблемами с кодировщиком Base64 Android SDK.   -  person drhr    schedule 18.07.2017


Ответы (2)


Я решил это следующим образом в классе, расширяющем okhttp3.RequestBody:

private void writeFile(File file, BufferedSink sink) throws IOException {
    byte buf[] = new byte[3000];
    try (FileInputStream fin = new FileInputStream(file)) {
        while (fin.read(buf) >= 0) {
            byte encoded[] = Base64.encodeBase64(buf);
            sink.write(encoded);
        }
    }
}

Он использует android.util.Base64 Apache Commons от Android org.apache.commons.codec.binary.Base64 для кодирования буферизованного блока данных.

В итоге я написал другие поля json отдельно, с достаточной степенью детализации, чтобы я мог вставить запись файла именно там, где мне нужно.

РЕДАКТИРОВАТЬ:

Как вы можете видеть из моих правок выше, в итоге я переключился на Apache commons-codec через compile 'commons-codec:commons-codec:1.5' в моем build.gradle файле.

У меня не было времени выяснить, почему решение Android SDK не работает. Я попробовал их Base64.encode(buf, Base64.NO_WRAP), как предлагалось в другом месте - предположительно, эквивалент encodeBase64(byte[]) Apache Commons, но это не сработало, отсюда и переключение.

Проблема могла быть в нашем бэкэнде, поэтому не исключайте решение Android SDK на основе одного только моего сообщения - я просто хотел добавить эту заметку, чтобы читатели могли увидеть фрагмент кода, который действительно сработал для меня в конце.

person drhr    schedule 27.06.2017

Только не с Гсоном или Моши. Обе эти библиотеки требуют, чтобы строки были в памяти перед отправкой их в поток.

person Jesse Wilson    schedule 20.06.2017