IllegalArgumentException using Java8 Base64 decoder

I wanted to use Base64.java to encode and decode files. Encode.wrap(InputStream) and decode.wrap(InputStream) worked, but they ran slowly. So I used the following code.

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

However he always throws

 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) ... 

After I changed final int BUFF_SIZE = 1024; on final int BUFF_SIZE = 3*1024; The code worked. Since "BUFF_SIZE" is also used to encode the file, I believe that something is wrong with the encoded file (1024% 3 = 1, which means that gaskets are added in the middle of the file).

Also, as @Jon Skeet and @Tagir Valeev mentioned, I should not ignore the return value from InputStream.read() . So, I changed the code as shown below.

(However, I have to mention that the code is much faster than using wrap() . I noticed a difference in speed because I encoded and heavily used Base64.encodeFile () / decodeFile () long before jdk8 came out. Now my jdk8 encoded code is as fast as my source code. So I don't know what happens with 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); } } 

Special thanks to @Jon Skeet and @Tagir Valeev.

+5
source share
4 answers

I strongly suspect that the problem is that you are ignoring the return value from InputStream.read , except for checking the end of the stream. So:

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

it should be

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

I would not expect this to be faster than using wrap .

+5
source

Try using decode.wrap(new BufferedInputStream(new FileInputStream(inputFileName))) . Buffering should be no less fast than your manual version.

As for why your code is not working: because the last fragment may be less than 1024 bytes, but you are trying to decode the entire byte[] array. See @JonSkeet answer for more.

+1
source

Well, I changed

"final int BUFF_SIZE = 1024;"

in

"final int BUFF_SIZE = 1024 * 3;"

It worked!

So, I think that maybe something is wrong with the addition ... I mean that when encoding a file (with 1024% 3 = 1) there should be paddings. And this can cause decoding problems ...

0
source
  • You must write the number of bytes read, other than this,
  • You must be sure that the size of your buffer is divided by 3, call in Base64, every 3 bytes have four outputs (64 is 2 ^ 6 and 3 * 8 is 4 * 6), by doing this, you can avoid the filling problem. (Thus, your output will not have the wrong end "=")
0
source

Source: https://habr.com/ru/post/1232591/


All Articles