Outofmemoryerror ByteArrayOutputStream отправляет большой файл в WS
Я отправляю видео в веб-сервис и работает нормально с видео размером менее 10 МБ, если видео составляет около 12 МБ, выведите меня из ошибки:
Это мой код:
FileInputStream fileInputStream = new FileInputStream(fichero);
int bytesAvailable = fileInputStream.available();
int maxBufferSize = 1024 * 1024 * 2;
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
byte[] buffer = new byte[bufferSize];
int bytesRead = fileInputStream.read(buffer, 0, bufferSize);
while (bytesRead > 0) {
dos.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
// nuevos
byte byt[] = new byte[bufferSize];
fileInputStream.read(byt);
// nuevos
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
// esto es nuevo
dos.write(buffer, 0, bufferSize);
// ya no es nuevo
}
Я думаю, что это потому, что я буферизирую все видео, но я не знаю, как отправить это без сохранения в буфере.
Это ошибка стека:
08-31 08:54:20.925: E/AndroidRuntime(18476): Caused by: java.lang.OutOfMemoryError
08-31 08:54:20.925: E/AndroidRuntime(18476): at java.io.ByteArrayOutputStream.expand(ByteArrayOutputStream.java:91)
08-31 08:54:20.925: E/AndroidRuntime(18476): at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:216)
08-31 08:54:20.925: E/AndroidRuntime(18476): at org.apache.harmony.luni.internal.net.www.protocol.http.RetryableOutputStream.write(RetryableOutputStream.java:60)
08-31 08:54:20.925: E/AndroidRuntime(18476): at java.io.DataOutputStream.write(DataOutputStream.java:99)
08-31 08:54:20.925: E/AndroidRuntime(18476): at com.reparalia.movilidad.AdjuntarFicheros$SubeFichero.doInBackground(AdjuntarFicheros.java:702)
08-31 08:54:20.925: E/AndroidRuntime(18476): at com.reparalia.movilidad.AdjuntarFicheros$SubeFichero.doInBackground(AdjuntarFicheros.java:1)
Строка 702 - это dos.write(buffer, 0, bufferSize);
Есть ли способ отправить видео? Спасибо
3 ответа
ByteArrayOutputStream
начинается с выделения 32 байтов или объема памяти, указанного конструктором, по умолчанию. Когда этот буфер был заполнен, ByteArrayOutputStream
удваивает размер буфера. Для больших объектов это может быть реальной проблемой. Ваша лучшая альтернатива - либо
- Используйте размер буфера, указанный конструктором, или
- простираться
ByteArrayOutputStream
и переопределите методы записи, чтобы перераспределение было более выгодным для вашего потока.
Это происходит потому, что - если ни setFixedLengthStreamingMode(int), когда длина тела заранее известна, ни setChunkedStreamingMode(int) не установлены. В этом случае HttpURLConnection вынужден буферизовать все тело запроса в памяти перед его передачей, тратя впустую (и, возможно, исчерпывая) кучу и увеличивая задержку. Очень хорошо объяснено в ссылке - http://developer.android.com/reference/java/net/HttpURLConnection.html
Пожалуйста, добавьте следующую строку в ваш код - HttpUrlConnectionObject. setChunkedStreamingMode (maxBufferSize); для системного значения по умолчанию установлено 0 HttpUrlConnectionObject.setChunkedStreamingMode(0);
Это работает для меня.
Вместо того, чтобы писать код для копирования потока самостоятельно, вы можете попытаться использовать класс библиотеки для этого.
В Guava доступен класс ByteStreams. Если вы человек типа Commons IO, есть IOUtils.
В IOUtils ваш код будет выглядеть примерно так:
FileInputStream fileInputStream = new FileInputStream(fichero);
OutputStream dos = ...
IOUtils.copy(fileInputStream, dos);
Я упустил необходимую обработку исключений и закрытие потока.