Interesante, hice algunas pruebas aquí y de hecho arroja esa excepción cuando lee el Base64InputStream
usando un InputStreamReader
, independientemente de la fuente de la secuencia, pero funciona sin problemas cuando lo lee como flujo binario. Como lo mencionó Trashgod, la codificación Base64 está enmarcada. El InputStreamReader
debería haber invocado flush()
en el Base64InputStream
una vez más para ver si ya no devuelve más datos.
no veo otras maneras de solucionar esto que la implementación de su propia
Base64InputStreamReader
o
Base64Reader
. Esto es realmente un error, ver la respuesta de Keith.
Como solución, también puede almacenarlo en un BLOB en lugar de un CLOB en la base de datos y usar PreparedStatement#setBinaryStream()
en su lugar. No importa si se almacena como datos binarios o no. No desea tener datos tan grandes de Base64 para poder indexarlos o buscarlos de todos modos.
actualización: puesto que no es una opción y tener los chicos Apache Commons Codec para solucionar el Base64InputStream
error que me reportaron, como CODEC-101 podría tomar algún tiempo, se puede considerar utilizar otra tercera parte base 64 API. Encontré un here (dominio público, para que pueda hacer lo que quiera, incluso colocarlo en su propio paquete), lo probé aquí y funciona bien.
InputStream base64 = new Base64.InputStream(input, Base64.ENCODE);
Actualización 2: el tipo de códec Commons tiene fixed que sea muy pronto.
Index: src/java/org/apache/commons/codec/binary/Base64InputStream.java
===================================================================
--- src/java/org/apache/commons/codec/binary/Base64InputStream.java (revision 950817)
+++ src/java/org/apache/commons/codec/binary/Base64InputStream.java (working copy)
@@ -145,21 +145,41 @@
} else if (len == 0) {
return 0;
} else {
- if (!base64.hasData()) {
- byte[] buf = new byte[doEncode ? 4096 : 8192];
- int c = in.read(buf);
- // A little optimization to avoid System.arraycopy()
- // when possible.
- if (c > 0 && b.length == len) {
- base64.setInitialBuffer(b, offset, len);
+ int readLen = 0;
+ /*
+ Rationale for while-loop on (readLen == 0):
+ -----
+ Base64.readResults() usually returns > 0 or EOF (-1). In the
+ rare case where it returns 0, we just keep trying.
+
+ This is essentially an undocumented contract for InputStream
+ implementors that want their code to work properly with
+ java.io.InputStreamReader, since the latter hates it when
+ InputStream.read(byte[]) returns a zero. Unfortunately our
+ readResults() call must return 0 if a large amount of the data
+ being decoded was non-base64, so this while-loop enables proper
+ interop with InputStreamReader for that scenario.
+ -----
+ This is a fix for CODEC-101
+ */
+ while (readLen == 0) {
+ if (!base64.hasData()) {
+ byte[] buf = new byte[doEncode ? 4096 : 8192];
+ int c = in.read(buf);
+ // A little optimization to avoid System.arraycopy()
+ // when possible.
+ if (c > 0 && b.length == len) {
+ base64.setInitialBuffer(b, offset, len);
+ }
+ if (doEncode) {
+ base64.encode(buf, 0, c);
+ } else {
+ base64.decode(buf, 0, c);
+ }
}
- if (doEncode) {
- base64.encode(buf, 0, c);
- } else {
- base64.decode(buf, 0, c);
- }
+ readLen = base64.readResults(b, offset, len);
}
- return base64.readResults(b, offset, len);
+ return readLen;
}
}
Lo intenté aquí y funciona bien.
Sí, tienes razón. Este es un error en Base64InputStream. +1 para el caso de prueba que lo confirma. – BalusC
Reportado por cierto: https://issues.apache.org/jira/browse/CODEC-101 Dicho esto, todavía me pregunto sobre la coincidencia de que mi archivo de prueba fue de hecho un múltiplo de 3 bytes de longitud: o) – BalusC
Wow, gracias por confirmar eso, debo decir que estoy sorprendido de haber encontrado un error (sin querer). – karoberts