6

对于这个包,我接下来的一个步骤是编写一系列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 文件!

经过一些调试后,我注意到:

  • 打开PNGZipInputStream并没有失败......
  • ...并.getNextEntry()返回null!

我预计至少 .getNextEntry()会抛出ZipException.

为什么没有呢?如何可靠地检测文件是否为 zip?

进一步说明:这是针对Paths; 因此任何东西File都是不可用的。

4

1 回答 1

0

为什么没有呢?

好吧,JavaDoc forgetNextEntry()说 a ZipExceptionorIOException发生,

如果发生 ZIP 文件错误

如果发生 I/O 错误

分别。

基于这些非常有用的信息(咳嗽),我们不能假设它会在遇到无效条目时抛出异常。

如何可靠地检测文件是否为 zip?

ZIP 文件格式规范,最初是 PKZip,可以在这里找到。虽然这一切都很好读:),但请看第 4 节;4.3.16 尤其如此。它指定所有 ZIP 文件(甚至是空文件)都具有的“中央目录记录的结尾”。

于 2015-04-26T16:59:03.380 回答