2015-04-26 34 views
6

對於this package,我的下一步驟之一是編寫一系列FileTypeDetector,以使方法Files.probeContentType()比默認情況下更智能(默認提供的文件類型檢測器僅依賴於「文件擴展名」)。如何爲zip存檔編寫FileTypeDetector?

由於上述方法的javadoc提到,此方法依賴FileTypeDetector的實例在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測試this image

完全測試:

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都不可用。

回答

0

爲什麼不呢?

嗯,getNextEntry()的JavaDoc說,一個ZipExceptionIOException發生,

如果要是發生I/O錯誤發生了一個ZIP文件錯誤

分別爲

基於這些奇妙有用的信息(咳嗽),我們不能做任何假設,如果它遇到一個無效的條目會拋出異常。

如何可靠地檢測文件是否爲zip?

ZIP文件格式規範,最初是PKZip,可以找到here。雖然它的全部都是很好的閱讀:),請看第4節;特別是4.3.16。它指定了所有ZIP文件具有的「中央目錄記錄結束」(甚至是空的)。

+1

這不是一個空的zip文件將作爲標題。 – fge

+0

@fge你是對的,我已經更新了我的答案。 – pathfinderelite