Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/366.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用base64编码器和InputStreamReader时出现问题_Java_Encoding_Jdbc_Base64_Inputstreamreader - Fatal编程技术网

Java 使用base64编码器和InputStreamReader时出现问题

Java 使用base64编码器和InputStreamReader时出现问题,java,encoding,jdbc,base64,inputstreamreader,Java,Encoding,Jdbc,Base64,Inputstreamreader,我在数据库中有一些CLOB列,需要将Base64编码的二进制文件放入其中。 这些文件可能很大,所以我需要对它们进行流式处理,我无法一次读取全部内容 我正在使用org.apache.commons.codec.binary.Base64InputStream进行编码,我遇到了一个问题。我的代码基本上是这样的 FileInputStream fis = new FileInputStream(file); Base64InputStream b64is = new Base64InputStream

我在数据库中有一些CLOB列,需要将Base64编码的二进制文件放入其中。 这些文件可能很大,所以我需要对它们进行流式处理,我无法一次读取全部内容

我正在使用
org.apache.commons.codec.binary.Base64InputStream
进行编码,我遇到了一个问题。我的代码基本上是这样的

FileInputStream fis = new FileInputStream(file);
Base64InputStream b64is = new Base64InputStream(fis, true, -1, null);
BufferedReader reader = new BufferedReader(new InputStreamReader(b64is));

preparedStatement.setCharacterStream(1, reader);
当我运行上述代码时,我会在执行更新时得到其中一个
java.io.IOException:底层输入流返回零字节
,它被抛出到InputStreamReader代码的深处

为什么这不起作用?在我看来, Reader 会尝试从文件流中读取64个流,所有的内容都应该是快乐的。

为最高效率,考虑在A内包装。例如:


附录:由于填充为4个字符的倍数,请确认源代码未被截断。可能需要使用
flush()

这似乎是
Base64InputStream
中的一个错误。你说得对

您应该将此报告给ApacheCommons编解码器项目

简单测试用例:

import java.io.*;
import org.apache.commons.codec.binary.Base64InputStream;

class tmp {
  public static void main(String[] args) throws IOException {
    FileInputStream fis = new FileInputStream(args[0]);
    Base64InputStream b64is = new Base64InputStream(fis, true, -1, null);

    while (true) {
      byte[] c = new byte[1024];
      int n = b64is.read(c);
      if (n < 0) break;
      if (n == 0) throw new IOException("returned 0!");
      for (int i = 0; i < n; i++) {
        System.out.print((char)c[i]);
      }
    }
  }
}
import java.io.*;
导入org.apache.commons.codec.binary.Base64InputStream;
类tmp{
公共静态void main(字符串[]args)引发IOException{
FileInputStream fis=新的FileInputStream(args[0]);
Base64InputStream b64is=新的Base64InputStream(fis,true,-1,null);
while(true){
字节[]c=新字节[1024];
int n=b64is.read(c);
如果(n<0)断裂;
如果(n==0)抛出新IOException(“返回0!”);
对于(int i=0;i

InputStream
read(byte[])
调用不允许返回0。在任何长度为3字节倍数的文件上,它都会返回0。

有趣的是,我在这里做了一些测试,当您使用
InputStreamReader
读取
Base64InputStream时,它确实会抛出该异常,而不管流的源是什么,但当您将其作为二进制流读取时,它会完美地工作。正如垃圾神提到的,Base64编码是有框架的。实际上,
InputStreamReader
应该再次调用
Base64InputStream
上的
flush()
,查看它是否没有返回更多数据

除了实现您自己的
Base64InputStreamReader
Base64Reader
之外,我看不到其他解决方法。这实际上是一个bug,参见Keith的答案

作为一种解决方法,您也可以将其存储在数据库中的BLOB而不是CLOB中,并使用
PreparedStatement\setBinaryStream()
。它是否存储为二进制数据并不重要。无论如何,您都不希望有这么大的Base64数据是可索引或可搜索的


<强>更新< /强>:因为这不是一个选项,并且让Apache Calm编解码器的家伙修复<代码> Base64 IndoStuts Bug,我说这可能需要一些时间,您可以考虑使用另一个第三方Base64 API。我已经找到了一个(公共域,所以你可以用它做任何你想做的事情,甚至放在你自己的包中),我在这里测试了它,它工作得很好

InputStream base64 = new Base64.InputStream(input, Base64.ENCODE);

更新2:commons编解码器的家伙很快就拥有了它

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;
         }
     }

我在这里试过,效果很好

也许它更有效,但它并不能解决问题——您的流是否有可能被截断?IIRC,
base64
被框定。问题已更新。你能详细解释一下你所说的“base64是框架的”是什么意思吗?流直接来自文件。编码流必须填充为“4个字符的整数倍”,以便解码最后一个字节;如果流被截断,这将是一个问题。上面引用的参考。@trashgod-“上面引用的参考。”。在哪里?是的,你是对的。这是Base64InputStream中的一个错误+1对于证实这一点的测试用例。报告顺便说一句,我仍然想知道我的测试文件确实是3字节长的倍数的巧合:o)哇,感谢你的确认,我必须说我很惊讶我发现了这样一个bug(无论多么不经意)。不幸的是,我不能使用BLOB,因为其中的数据有时会有文本
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;
         }
     }