Разница между FileInputStream и ByteArrayInputStream

Я пытаюсь прочитать тип файла, используя два способа. Работает при использовании ByteArrayInputStream но нет FileInputStream

С помощью FileInputStream с URLConnection,

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

С помощью ByteArrayInputStream с URLConnection

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

Почему разница в результате? Кроме того, есть ли где-нибудь упомянутое для использования только ByteArrayInputStream читать тип файла?

2 ответа

Решение

Техника URLConnection.guessContentTypeFromStream это посмотреть на первые байты, так называемый волшебный cookie, чтобы идентифицировать файл.

Разработчики решили оставить Stream в неизмененном состоянии, поэтому продолжение чтения начнется (снова) с начала.

Для этого он делает reset(): на предыдущую отмеченную позицию потока (фактическое начало).

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();
    ....

Для последовательного FileInputStream markSupported() возвращает значение по умолчанию false,

Это можно решить, обернув FileInputStream по BufferedInputStream, который был бы быстрее в любом случае.

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

Обратите внимание, что Files.newInputStream как указано в Javadoc не будет поддерживать маркировку позиции для сброса.

(Используя ByteArrayInputStream было бы слишком большими накладными расходами.)

Хотя два типа входных потоков различаются во многих отношениях, причина такого поведения связана только с поддержкой маркировки / сброса этих двух потоков.

Если вы проверите источник URLConnection.guessContentTypeFromStreamвы заметите:

// If we can't read ahead safely, just give up on guessing
if (!is.markSupported())
    return null;

А также ByteArrayInputStream Переопределение markSupported возвращать true в то время как FileInputStream наследует по умолчанию InputStream.markSupported метод, который возвращает false,

Другими словами, guessContentTypeFromStream не может работать с потоком ввода файла (или любым потоком, который не поддерживает метку / сброс).

Другие вопросы по тегам