对于这个包,我接下来的一个步骤是编写一系列FileTypeDetector
让该方法Files.probeContentType()
比默认情况下更智能(默认提供的文件类型检测器仅依赖于“文件扩展名”)。
正如上述方法的 javadoc 所提到的,该方法依赖于在文件FileTypeDetector
中声明的 s实例。META-INF/services
我首先使用一个简单的提供程序进行了测试,以使用文件头检测 PNG 文件:
public final class PngFileTypeDetector
extends FileTypeDetector
{
private static final byte[] PNG_HEADER = {
(byte) 0x89,
(byte) 0x50, (byte) 0x4E, (byte) 0x47,
(byte) 0x0D, (byte) 0x0A,
(byte) 0x1A,
(byte) 0x0A
};
private static final int PNG_HEADER_SIZE = PNG_HEADER.length;
@Override
public String probeContentType(final Path path)
throws IOException
{
final byte[] buf = new byte[PNG_HEADER_SIZE];
try (
final InputStream in = Files.newInputStream(path);
) {
if (in.read(buf) != PNG_HEADER_SIZE)
return null;
}
return Arrays.equals(buf, PNG_HEADER) ? "image/png" : null;
}
}
有用。现在,在快速浏览 API 之后,我认为这是检测文件是否为 zip 文件的好方法:
public final class ZipFileTypeDetector
extends FileTypeDetector
{
@Override
public String probeContentType(final Path path)
throws IOException
{
// Rely on what the JDK has to offer...
try (
final InputStream in = Files.newInputStream(path);
final ZipInputStream z = new ZipInputStream(in);
) {
z.getNextEntry();
return "application/zip";
} catch (ZipException ignored) {
return null;
}
}
}
的内容META-INF/services/java.nio.file.spi.FileTypeDetector
是这样的:
com.github.fge.filesystem.ftd.PngFileTypeDetector
com.github.fge.filesystem.ftd.ZipFileTypeDetector
通过当前的测试,它起作用了;对于 zip,我创建了一个空的 zip 文件,对于 PNG 测试,我使用了这个图像。
全面测试:
public final class FileTypeDetectorTest
{
private FileSystem fs;
private Path path;
@BeforeMethod
public void initfs()
throws IOException
{
fs = MemoryFileSystemBuilder.newLinux().build("testfs");
path = fs.getPath("/foo");
}
@DataProvider
public Iterator<Object[]> samples()
{
final List<Object[]> list = new ArrayList<>();
String resourcePath;
String mimeType;
resourcePath = "/ftd/sample.png";
mimeType = "image/png";
list.add(new Object[] { resourcePath, mimeType });
resourcePath = "/ftd/sample.zip";
mimeType = "application/zip";
list.add(new Object[] { resourcePath, mimeType });
return list.iterator();
}
@Test(dataProvider = "samples")
public void fileTypeDetectionTest(final String resourcePath,
final String mimeType)
throws IOException
{
@SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
final InputStream in
= FileTypeDetectorTest.class.getResourceAsStream(resourcePath);
if (in == null)
throw new IOException(resourcePath + " not found in classpath");
try (
final InputStream inref = in;
) {
Files.copy(inref, path);
}
assertThat(Files.probeContentType(path)).isEqualTo(mimeType);
}
@AfterMethod
public void closefs()
throws IOException
{
fs.close();
}
}
然而...
如果我反转服务文件中的实现列表,那么现在的文件是:
com.github.fge.filesystem.ftd.ZipFileTypeDetector
com.github.fge.filesystem.ftd.PngFileTypeDetector
然后 PNG 文件被检测为 zip 文件!
经过一些调试后,我注意到:
- 打开PNG
ZipInputStream
并没有失败...... - ...并
.getNextEntry()
返回null!
我预计至少 .getNextEntry()
会抛出ZipException
.
为什么没有呢?如何可靠地检测文件是否为 zip?
进一步说明:这是针对Path
s; 因此任何东西File
都是不可用的。