Интересно, что я провел здесь несколько тестов, и это действительно выдает это исключение, когда вы читаете Base64InputStream
, используя InputStreamReader
, независимо от источника потока, но оно работает безупречно, когда вы читаете его как двоичный поток. Как упомянул Trashgod, кодировка Base64 оформлена. InputStreamReader
на самом деле должен был бы вызвать flush()
на Base64InputStream
еще раз, чтобы проверить, не возвращает ли он больше данных.
Я не вижу других способов исправить это, кроме реализации ваших собственных Base64InputStreamReader
или Base64Reader
. На самом деле это ошибка, см. Ответ Кита.
В качестве обходного пути вы также можете просто сохранить его в BLOB вместо CLOB в БД и использовать вместо него PreparedStatement#setBinaryStream()
. Неважно, хранятся ли они как двоичные данные или нет. Вы не хотите, чтобы такие большие данные Base64 были индексируемыми или доступными для поиска в любом случае.
Обновление : поскольку это не вариант, и если парни из Apache Commons Codec исправят ошибку Base64InputStream
, о которой я сообщал как CODEC-101 , это может занять некоторое время, вы можете рассмотреть возможность использования другого стороннего Base64 API. Я нашел один здесь (общественное достояние, так что вы можете делать с ним все, что захотите, даже поместить в свой собственный пакет), я протестировал его здесь, и он отлично работает.
InputStream base64 = new Base64.InputStream(input, Base64.ENCODE);
Обновление 2 : парень с кодеками общего пользования исправил довольно скоро.
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;
}
}
Я попробовал это здесь, и оно отлично работает.