使用Java8 Base64解码器的非法参数异常



我想使用Base64.java对文件进行编码和解码。Encode.wrap(InputStream)decode.wrap(InputStream)工作,但运行缓慢。所以我使用了下面的代码。

public static void decodeFile(String inputFileName,
        String outputFileName)
        throws FileNotFoundException, IOException {
    Base64.Decoder decoder = Base64.getDecoder();
    InputStream in = new FileInputStream(inputFileName);
    OutputStream out = new FileOutputStream(outputFileName);
    byte[] inBuff = new byte[BUFF_SIZE];  //final int BUFF_SIZE = 1024;
    byte[] outBuff = null;
    while (in.read(inBuff) > 0) {
        outBuff = decoder.decode(inBuff);
        out.write(outBuff);
    }
    out.flush();
    out.close();
    in.close();
}
然而,它总是抛出
Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: Input byte array has wrong 4-byte ending unit
    at java.util.Base64$Decoder.decode0(Base64.java:704)
    at java.util.Base64$Decoder.decode(Base64.java:526)
    at Base64Coder.JavaBase64FileCoder.decodeFile(JavaBase64FileCoder.java:69)
    ...

final int BUFF_SIZE = 1024;改为final int BUFF_SIZE = 3*1024;后,代码正常运行。由于"BUFF_SIZE"也用于编码文件,我认为编码的文件有问题(104% 3 = 1,这意味着在文件中间添加了填充)。

同样,正如@Jon Skeet和@Tagir Valeev提到的,我不应该忽略InputStream.read()的返回值。因此,我将代码修改如下:

(然而,我不得不提的是,代码运行得比使用wrap()快得多。我注意到速度上的差异,因为早在jdk8发布之前,我就已经编码并大量使用了Base64.encodeFile()/decodeFile()。现在,经过优化的jdk8代码运行起来和原来的代码一样快。所以,我不知道wrap()是怎么回事…)

public static void decodeFile(String inputFileName,
        String outputFileName)
        throws FileNotFoundException, IOException
{
    Base64.Decoder decoder = Base64.getDecoder();
    InputStream in = new FileInputStream(inputFileName);
    OutputStream out = new FileOutputStream(outputFileName);
    byte[] inBuff = new byte[BUFF_SIZE];
    byte[] outBuff = null;
    int bytesRead = 0;
    while (true)
    {
        bytesRead = in.read(inBuff);
        if (bytesRead == BUFF_SIZE)
        {
            outBuff = decoder.decode(inBuff);
        }
        else if (bytesRead > 0)
        {
            byte[] tempBuff = new byte[bytesRead];
            System.arraycopy(inBuff, 0, tempBuff, 0, bytesRead);
            outBuff = decoder.decode(tempBuff);
        }
        else
        {
            out.flush();
            out.close();
            in.close();
            return;
        }
        out.write(outBuff);
    }
}

特别感谢@Jon Skeet和@Tagir Valeev。

我强烈怀疑问题是您忽略了InputStream.read的返回值,而不是检查流的结束。所以这:

while (in.read(inBuff) > 0) {
    // This always decodes the *complete* buffer
    outBuff = decoder.decode(inBuff);
    out.write(outBuff);
}
应该

int bytesRead;
while ((bytesRead = in.read(inBuff)) > 0) {
    outBuff = decoder.decode(inBuff, 0, bytesRead);
    out.write(outBuff);
}

我不会期望这比使用wrap更快。

尝试使用decode.wrap(new BufferedInputStream(new FileInputStream(inputFileName)))。有了缓冲,它应该至少和你手工制作的版本一样快。

至于为什么你的代码不工作:那是因为最后一块可能短于1024字节,但你试图解码整个byte[]数组。

我改变了

"final int BUFF_SIZE = 1024;"

"final int BUFF_SIZE = 1024 * 3;"

工作!

所以,我猜可能是填充有问题…我的意思是,当编码文件时,(因为104% 3 = 1)必须有填充。这些可能会在解码时产生问题……

  • 你应该记录你已经读取的字节数,在此旁边,
  • 你应该确保你的缓冲区大小可以被3整除,因为在Base64中,每3个字节有4个输出(64是2^6,3*8等于4*6),通过这样做,你可以避免填充问题。(这样你的输出就不会有错误的"="结尾)

相关内容

  • 没有找到相关文章

最新更新