javafileinputstreambytearrayinputstream

Difference between FileInputStream and ByteArrayInputStream


I try to read file type using two ways. It is working while using ByteArrayInputStream but not FileInputStream

Using FileInputStream with URLConnection,

String fileType = URLConnection
  .guessContentTypeFromStream(
    new FileInputStream(new File("C:\\image.jpeg"))
   ); //fileType = null

Using ByteArrayInputStream with URLConnection

String fileType = URLConnection
.guessContentTypeFromStream(
  new ByteArrayInputStream(Files.readAllBytes(new File("C:\\image.jpeg").toPath()))
 ); //fileType = image/jpeg

Why is the difference in the result ? Also, is there anywhere mentioned to use only ByteArrayInputStream to read the file type?


Solution

  • The technique of URLConnection.guessContentTypeFromStream is to look at the first bytes, the so called magic cookie to identify the file.

    The implementors chose to leave the Stream in an unaltered state, so continue reading will start (again) with at the beginning.

    For that it does a reset(): to the previous marked stream position (actual the beginning).

    static public String guessContentTypeFromStream(InputStream is)
                        throws IOException {
        // If we can't read ahead safely, just give up on guessing
        if (!is.markSupported())
            return null;
    
        is.mark(16);
        int c1 = is.read();
        int c2 = is.read();
        int c3 = is.read();
        ...
        int c14 = is.read();
        int c15 = is.read();
        int c16 = is.read();
        is.reset();
        ....
    

    For a sequential FileInputStream markSupported() returns the default false.

    One can solve it by wrapping the FileInputStream by a BufferedInputStream, which would be faster anyhow.

    String fileType = URLConnection
        .guessContentTypeFromStream(
            new BufferedInputStream(Files.newInputStream(Paths.get("C:\\image.jpeg")))
         );
    

    Note that Files.newInputStream as stated in the javadoc will not support marking a position for reset.

    (Using a ByteArrayInputStream would be a too large overhead.)