2015-04-26 3 views
6

Для this package один из моих следующих шагов - написать серию из FileTypeDetector, чтобы метод Files.probeContentType() был более умным, чем тот, который по умолчанию (детектор типа данных по умолчанию использует только расширения имен файлов).Как написать FileTypeDetector для zip-архивов?

Как указано в 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, я думал, что это будет хорошим способом обнаружить, был ли файл почтового индекса:

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 я создал пустой почтовый файл, для теста 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() возвращается нуль!

я ожидал по крайней мере.getNextEntry() бросить ZipException.

Почему не так ли? Как я могу надежно определить, является ли файл почтовым индексом?

Примечание: для Path s; поэтому все File непригодный для использования.

ответ

0

Почему не так ли?

Ну, JavaDoc для getNextEntry() говорит, что ZipException или IOException происходит,

если ошибка ZIP файл произошла

, если произошла ошибка ввода/вывода

соответственно.

Основываясь на этой чудесно полезной информации (cough), мы не можем делать никаких предположений о том, что она будет генерировать исключение, если встречается с недопустимой записью.

Как я могу надежно определить, является ли файл почтовым индексом?

Спецификация формата файла ZIP, которая была изначально PKZip, находится в here. В то время как все это хорошо читается :), взгляните на раздел 4; 4.3.16 в частности. Он определяет «Конец записи центрального каталога», который имеет все файлы ZIP (даже пустые).

+1

Это не то, что пустой почтовый файл будет иметь как заголовок. – fge

+0

@fge Вы правы, я обновил свой ответ. – pathfinderelite