When there is a range request, FileSystemResource will get an InputStream via File.newInputStream(Path). This InputStream is provided by FileSystemProvider.newInputStream() which uses Channels.newInputStream(), creating a very basic InputStream.

The problem arise with skip function, which Channels provide a very basic InputStream that skips n bytes by reading n bytes into memory and throws it away, instead of using SEEK even though it is a file. This makes loading take more than 5000 ms when I try to request a range in the middle of a 3GB file.

I use this for a personal file server for video streaming, which when dealing with big files, there is a big latency the further I skip in the video.

I currently have a work around on my server where I extend the FileSystemResource and use new FileInputStream() in the overridden getInputStream() instead since its skip function is mapped to a native function using seek. This significantly reduces the latency, like sub-second latency vs 5000+ms previously.

Comment From: sbrannen

As a side note, the Javadoc for java.io.InputStream.skip(long) states the following (with bold emphasis from me):

The skip method of this class creates a byte array and then repeatedly reads into it until n bytes have been read or the end of the stream has been reached. Subclasses are encouraged to provide a more efficient implementation of this method. For instance, the implementation may depend on the ability to seek.

Comment From: khangp0000

Honestly, I cannot find any real reason why we are using NIO api while still using Stream internally. NIO file operations only improve if you also use Channel for network Socket and use FileChannel.transferTo() which use native call. Otherwise, if you are sticking with InputStream and OutputStream, using original IO api is good enough, if not better.

This is my very naïve view of NIO, please correct me if I'm wrong about the purpose of using NIO.

Comment From: khangp0000

@sbrannen

After further investigation, it seems newer version of OpenJDK https://bugs.openjdk.java.net/browse/JDK-8227080

For java 11, it require 11.0.12 (which is the newest java version that release a month ago)

Sadly this update was not applied for java 8. It is not an issue for me but maybe for other who still use java 8. Since spring still support java 8, I don't know if I should close this issue or not. Please decide on this accordingly.

Comment From: rstoyanchev

@khangp0000 thanks for the the update. Some further background on the original change to switch from FileInputStream and FileOutputStream in https://github.com/spring-projects/spring-framework/issues/20304#issuecomment-453458235. Keep in mind also that in addition to exposing InputStream and OutputStream, FileSystemResource also exposes NIO channels, and we do use that in WebFlux.

In light of that, I'm closing this in favor of the JDK fix.