JDK-6402006 : FileInputStream.available() returns negative values when reading a large file
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.io
  • Affected Version: 5.0
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2006-03-22
  • Updated: 2011-03-07
  • Resolved: 2011-03-07
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7
7 b123Fixed
Related Reports
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.5.0_06"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_06-b05)
Java HotSpot(TM) Client VM (build 1.5.0_06-b05, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]


A DESCRIPTION OF THE PROBLEM :
When reading a large file using FileInputStream, the available() method returns negative values after a certain point. For example, I created a file 7,405,576,182 bytes long, and seeked 3,110,608,892 bytes into the file. The available() method returned -5. I tried this on 3 different Windows boxes with different versions of Java and I found the exact same problem on all of them.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
* Create a file 7,405,576,182 bytes long.
* Open the file using FileInputStream.
* Seek 3,110,608,892 bytes into the file.
* Call the available() method and check the result.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I would expect a positive number.
ACTUAL -
The funtion returned -5.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
// WARNING: This program creates a 6.9 GB file. Ensure you have sufficient space before running it.

import java.io.*;

public class Test
{
	public static void main(String[] args) throws IOException
	{
		File file = new File("x");

		RandomAccessFile raf = new RandomAccessFile(file, "rw");
		raf.seek(7405576182L);
		raf.write(1);
		raf.close();

		FileInputStream fis = new FileInputStream(file);
		fis.skip(3110608882L);
		System.out.println(fis.available());
		fis.skip(10L);
		System.out.println(fis.available());
		fis.close();

		file.delete();
	}
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
I worked around this problem by creating a wrapper class for FileInputStream with a different implementation of the available() method which returned the number of bytes between the current file pointer and the end of the file.

Comments
EVALUATION http://hg.openjdk.java.net/jdk7/build/jdk/rev/8b2025d6f257
25-12-2010

EVALUATION Changeset URL: http://hg.openjdk.java.net/jdk7/tl/jdk/rev/8b2025d6f257
02-12-2010

SUGGESTED FIX $ hg diff io_util_md.c diff --git a/src/windows/native/java/io/io_util_md.c b/src/windows/native/java/io/io_util_md.c --- a/src/windows/native/java/io/io_util_md.c +++ b/src/windows/native/java/io/io_util_md.c @@ -335,10 +335,11 @@ return FALSE; } current = (((jlong)highPos) << 32) | lowPos; - end = GetFileSize(h, &sizeHigh); + sizeLow = GetFileSize(h, &sizeHigh); if (sizeLow == ((DWORD)-1)) { return FALSE; } + end = (((jlong)sizeHigh) << 32) | sizeLow; *pbytes = end - current; return TRUE; }
10-11-2010

EVALUATION It is a bug in the windows implementation to determine the end of the file which ignores the high-order doubleword of the file size. Thus the available() method returns only the low-order 32-bit for large files.
10-11-2010

EVALUATION BufferedInputStream.available() has similar problems as described in 6631046. Both of theses bugs should be examined/fixed simultaneously. It is possible that all of the available() methods in this package may suffer from similar problems, so they should all be examined.
25-01-2008