Разница между 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
не может работать с потоком ввода файла (или любым потоком, который не поддерживает метку / сброс).