FULL PRODUCT VERSION :
$ java -version
java version "1.6.0_03"
Java(TM) SE Runtime Environment (build 1.6.0_03-b05)
Java HotSpot(TM) Server VM (build 1.6.0_03-b05, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
$ uname -a
Linux david 2.6.22-14-generic #1 SMP Sun Oct 14 23:05:12 GMT 2007 i686 GNU/Linux
kfc@david:~$ java -version
A DESCRIPTION OF THE PROBLEM :
InputStream.available() returns an int. For streams larger than 2GB this might be a problem, and a reasonable choice is to return Integer.MAX_VALUE in that case. This is the behavior of FileInputStream().
However, a stream with this behaviour will malfunction if wrapped in a BufferedInputStream, since the implementation if "available()" in BufferedInputStream.available() returns in.available() + (count - pos), which will give an overflow and return a negative size.
This is the implementation of BufferedInputStream.available():
public synchronized int available() throws IOException {
return getInIfOpen().available() + (count - pos);
}
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Make a 3 GB file "x.foo".
Run the test program below.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Same behaviour on buffered and unbuffered inputstream:
Integer.MAX_VALUE returned in all cases.
FileInputStream:
2147483647
2147483647
BufferedInputStream:
2147483647
2147483647
ACTUAL -
Negative results from BufferedOutputStream
FileInputStream:
2147483647
2147483647
BufferedInputStream:
2147483647
-2147475458
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
// Assumes existence of a 3 GB file "x.foo".
import java.io.*;
public class X {
public static void main(String... args) throws Exception {
System.out.println("FileInputStream:");
InputStream is = new FileInputStream("x.foo");
System.out.println(is.available());
is.read();
System.out.println(is.available());
System.out.println("BufferedInputStream:");
is = new BufferedInputStream(new FileInputStream("x.foo"));
System.out.println(is.available());
is.read();
System.out.println(is.available());
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Make a subclass of BufferedInputStream and override available(). Only possible if you are in charge of the InputStreams you receive.