Dla this package, jednym z moich kolejnych kroków jest napisanie serii FileTypeDetector
, aby metoda była domyślnie inteligentniejsza niż domyślna (domyślny dostarczony typ pliku opiera się tylko na "rozszerzeniach nazw plików").Jak napisać FileTypeDetector dla archiwów zip?
Jak wspomina javadoc wspomnianej powyżej metody, ta metoda polega na wystąpieniu instancji FileTypeDetector
s zadeklarowanych w pliku.
ja najpierw testowane za pomocą prostego dostawcy wykryć pliki PNG za pomocą nagłówka pliku:
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;
}
}
To działa. Teraz, po szybkim spojrzeniu na API, myślałem, że będzie to dobry sposób, aby wykryć, czy plik był błyskawiczny:
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;
}
}
}
Zawartość META-INF/services/java.nio.file.spi.FileTypeDetector
było to:
com.github.fge.filesystem.ftd.PngFileTypeDetector
com.github.fge.filesystem.ftd.ZipFileTypeDetector
Z aktualne testy, zadziałało; dla zipu stworzyłem pusty plik zip, dla testu PNG użyłem this image.
Pełny Test:
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();
}
}
Jednak ...
Gdybym odwrócić listę wdrożeń w pliku services, czyli plik teraz jest:
com.github.fge.filesystem.ftd.ZipFileTypeDetector
com.github.fge.filesystem.ftd.PngFileTypeDetector
wówczas Plik PNG jest wykrywany jako plik zip!
Po pewnym debugowania zauważyłem, że:
- otwarciu PNG jako
ZipInputStream
nie zawiódł ... - ... i
.getNextEntry()
powrócił zerowa!
bym oczekiwać przynajmniej.getNextEntry()
rzucać ZipException
.
Dlaczego nie? Jak wykryć niezawodnie, czy plik jest zip?
Dalsza uwaga: dotyczy to Path
s; w związku z tym wszystko, co jest File
, jest bezużyteczne.
Nie jest to jednak pusty plik zip jako nagłówek. – fge
@fge Masz rację, zaktualizowałem swoją odpowiedź. – pathfinderelite