我使用此函数获取文件 contentType ,当使用 .jpg 文件时接收“image/jpg”。使用 .mp4 接收“video/quicktime”
public static String detectMediaType(String fileName,byte[] data) {
ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
AutoDetectParser parser = new AutoDetectParser();
Detector detector = parser.getDetector();
Metadata md = new Metadata();
md.add(Metadata.RESOURCE_NAME_KEY, fileName);
try{
MediaType mediaType = detector.detect(inputStream, md);
return mediaType.toString();
}catch (IOException ex){
throw new RuntimeException("Failed to detect mediaType for file: " + fileName,ex);
}
}
我遇到了同样的问题,并且想知道为什么在使用上面的答案后我仍然得到“video/quicktime”作为 Mimetype。总结一下一切:
使用解析器来检测元数据(如第一个答案)
使用TikaInputStream(如第二个答案中所示),但不要尝试重用它
在依赖项中包含适合您的情况的特定解析器(在本例中是 org.apache.tika.parser.mp4.MP4Parser
Tika tika = new Tika();
String detectedType;
try (
TikaInputStream parserInputStream = TikaInputStream.get(new ByteArrayInputStream(bytes));
TikaInputStream detectionInputStream = TikaInputStream.get(new ByteArrayInputStream(bytes));
) {
// reading metadata from file, important for video type detection (quicktime, mp4, ...)
Parser parser = new AutoDetectParser();
BodyContentHandler handler = new BodyContentHandler();
Metadata metadata = new Metadata();
ParseContext context = new ParseContext();
parser.parse(parserInputStream, handler, metadata, context);
// read the type
// would like to reuse the stream from above (used by parser), but this can end in a wrong mimetype
// parserInputStream.reset();
detectedType = tika.detect(detectionInputStream, metadata);
} catch (Exception ex) {
detectedType = tika.detect(bytes);
log.warn("Could not read MimeType of file '{}' using Metadata, using fallback detection: '{}'", file.getOriginalFilename(), detectedType);
}
依赖关系,例如在 Maven 中:
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-parser-audiovideo-module</artifactId>
<scope>runtime</scope>
</dependency>
这是预期的,因为您正在使用 tika 检测器功能,该功能对于 mp4 或其他 QuickTime 格式返回通用“视频/quicktime”。如果您需要获得像“video/mp4”这样的精确类型,您应该另外使用 tika 解析器,例如:
if (mediaType.equals(MediaType.video("quicktime"))) {
Parser parser = new AutoDetectParser();
ContentHandler handler = new BodyContentHandler();
Metadata metadata = new Metadata();
ParseContext context = new ParseContext();
parser.parse(inputStream, handler, metadata, context);
}
我在使用 Tikas DefaultDetector 时遇到了同样的问题。
解决方案,如下所示:https://tika.apache.org/2.3.0/detection.html(在“容器感知检测”下),是使用
TikaInputStream
,而不是标准 InputStream
.
detector.detect(TikaInputStream.get(inputStream), metadata);
tika-parsers-*
jar 位于类路径中。在这里对其他答案添加一些澄清。
@uhon的答案仅在使用
TikaInputStream.get
或File
调用静态Path
方法时才会产生影响,以便Tika可以根据文件名添加一些元数据。当 Tika 看到 .mp4
扩展名时,它将通过将 MP4Parser
应用于问题来触发 Tika 的容器感知检测。
如果输入是
byte[]
,则只需将其包装在 TikaInputStream
中而不在 MetaData
参数中提供文件名将不会有任何区别,因为 TikaInputStream
没有额外的元数据可提供。
@Dasch33的答案基本上是正确的,除了如果你已经知道你将使用重量级解析器而不仅仅是检测器,
TikaInputStream
对于这个用例没有任何区别。请注意,额外的元数据可能会对其他容器类型(例如 zip 和 OLE2)产生影响,但在我的测试中它不会影响 MP4 视频的解析
-- Tika 的解析器足够聪明,可以在没有它的情况下委托给它的 MP4Parser
。将任何内容(包括 ByteArrayInputStream
)传递给解析器将正确检测 video/mp4
。
@zygimantus 的答案最接近目标,首先使用轻量级检测器,然后有条件地应用较重的解析来缩小视频类型的范围。然而,没有必要创建所有这些对象,并且它没有进行适当的资源管理。解决方案可以很简单:
// if your input is an InputStream or File or Path
// it can be passed directly to `tika.parse`.
byte[] input = ...
var metaData = new MetaData()
try(var ignored = tika.parse(new ByteArrayInputStream(input), metaData)) { } catch (IOException e) { ... }
var mime = metaData.get(Metadata.CONTENT_TYPE);
对 tika.parse
的调用会返回
Reader
,提供对输入文本内容的访问。在这里,对于这个用例,我们不关心文本内容——我们只需要解析器提供的高级检测功能。但尽管如此,返回的 reader 负责关闭流资源,因此我们需要将其封装在 try-with-resources 中。