What is the reason for java.io.IOException: Underl

2019-07-16 03:22发布

问题:

Here is my code, imageFile is a pdf file, intent is to get Base64 encoded file for image file. I am using Java6 and no possibility to upgrade to Java7

Base64Inputstream is of type org.apache.commons.codec.binary.Base64InputStream

private File toBase64(File imageFile) throws Exception {
         LOG.info(this.getClass().getName() + " toBase64 method is called");
         System. out.println("toBase64 is called" );
         Base64InputStream in = new Base64InputStream(new FileInputStream(imageFile), true );
         File f = new File("/root/temp/" + imageFile.getName().replaceFirst("[.][^.]+$" , "" ) + "_base64.txt" );
         Writer out = new FileWriter(f);
         copy(in, out);
         return f;
  }

 private void copy(InputStream input, Writer output)
            throws IOException {
        InputStreamReader in = new InputStreamReader(input);
        copy(in, output);
    }

 private int copy(Reader input, Writer output) throws IOException {
        long count = copyLarge(input, output);
        if (count > Integer.MAX_VALUE) {
            return -1;
        }
        return (int) count;
    }

 private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;

 private long copyLarge(Reader input, Writer output) {
        char[] buffer = new char[DEFAULT_BUFFER_SIZE];
        long count = 0;
        int n = 0;
        try {
            while (-1 != (n = input.read(buffer))) {
                output.write(buffer, 0, n);
                count += n;
                System.out.println("Count: " + count);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return count;
    }

I was using IOUtils.copy(InputStream input, Writer output) method. But for some pdf files (note, not all) it throws exception. So, in the process of debugging I copied IOUtils.copy code locally and exception is thrown after Count: 2630388. This is the stack trace:

Root Exception stack trace:
java.io.IOException: Underlying input stream returned zero bytes
    at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:268)
    at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)

Under what situations can this block above said throw exception:

while (-1 != (n = input.read(buffer))) {
                    output.write(buffer, 0, n);
                    count += n;
                    System.out.println("Count: " + count);
                }

Please help me understand the cause and how can I fix it

回答1:

You should not use Reader/Writer which are text oriented and not binary, at least without encoding. They use an encoding. And PDF is binary. Either explicitly given, or the default OS encoding (unportable).

For InputStream use readFully.

And then do always a close(). The copy method, maybe leaving the close to the callers, could at least call flush() in that case.


In Java 7 there already exists a copy, but needs a Path and an extra option.

private File toBase64(File imageFile) throws Exception {
    LOG.info(this.getClass().getName() + " toBase64 method is called");
    System.out.println("toBase64 is called");
    Base64InputStream in = new Base64InputStream(new FileInputStream(imageFile),
        true);
    File f = new File("/root/temp/" + imageFile.getName()
        .replaceFirst("[.][^.]+$", "") + "_base64.txt");

    Files.copy(in, f.toPath(), StandardCopyOption.REPLACE_EXISTING);
    in.close();

    return f;
}