Для 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
непригодный для использования.
Это не то, что пустой почтовый файл будет иметь как заголовок. – fge
@fge Вы правы, я обновил свой ответ. – pathfinderelite