Question simple: comment obtenir le type MIME (ou le type de contenu) d'une InputStream
sans enregistrer de fichier pour un fichier téléchargé par un utilisateur sur mon servlet?
Cela dépend d'où vous obtenez le flux d'entrée. Si vous l'obtenez à partir d'un servlet, il est accessible via l'objet HttpServerRequest qui est un argument de doPost. Si vous utilisez une sorte d'API restante telle que Jersey, la requête peut être injectée à l'aide de @Context. Si vous téléchargez le fichier via un socket, il vous incombe de spécifier le type MIME dans le cadre de votre protocole car vous n'hériterez pas des en-têtes http.
J'ai écrit mon propre détecteur de type de contenu pour un octet [] parce que les bibliothèques ci-dessus n'étaient pas adaptées ou que je n'y avais pas accès. Espérons que cela aide quelqu'un.
// retrieve file as byte[]
byte[] b = odHit.retrieve( "" );
// copy top 32 bytes and pass to the guessMimeType(byte[]) funciton
byte[] topOfStream = new byte[32];
System.arraycopy(b, 0, topOfStream, 0, topOfStream.length);
String mimeGuess = guessMimeType(topOfStream);
...
private static String guessMimeType(byte[] topOfStream) {
String mimeType = null;
Properties magicmimes = new Properties();
FileInputStream in = null;
// Read in the magicmimes.properties file (e.g. of file listed below)
try {
in = new FileInputStream( "magicmimes.properties" );
magicmimes.load(in);
in.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// loop over each file signature, if a match is found, return mime type
for ( Enumeration keys = magicmimes.keys(); keys.hasMoreElements(); ) {
String key = (String) keys.nextElement();
byte[] sample = new byte[key.length()];
System.arraycopy(topOfStream, 0, sample, 0, sample.length);
if( key.equals( new String(sample) )){
mimeType = magicmimes.getProperty(key);
System.out.println("Mime Found! "+ mimeType);
break;
} else {
System.out.println("trying "+key+" == "+new String(sample));
}
}
return mimeType;
}
exemple de fichier magicmimes.properties (pas sûr que ces signatures soient correctes, mais elles ont fonctionné pour mes utilisations)
# SignatureKey content/type
\u0000\u201E\u00f1\u00d9 text/plain
\u0025\u0050\u0044\u0046 application/pdf
%PDF application/pdf
\u0042\u004d image/bmp
GIF8 image/gif
\u0047\u0049\u0046\u0038 image/gif
\u0049\u0049\u004D\u004D image/tiff
\u0089\u0050\u004e\u0047 image/png
\u00ff\u00d8\u00ff\u00e0 image/jpg
Selon L’excellent site de Real Gagnon , la meilleure solution pour votre cas serait d’utiliser Apache Tika .
Vous pouvez vérifier le champ d'en-tête Content-Type
et consulter l'extension du nom de fichier used. Pour tout le reste, vous devez exécuter des routines plus complexes, telles que la vérification par Tika
etc.
Vous pouvez simplement ajouter le fichier tika-app-1.x.jar à votre chemin d'accès aux classes tant que vous n'utilisez pas la journalisation slf4j ailleurs, car cela provoquerait une collision. Si vous utilisez tika pour détecter un flux d'entrée, celui-ci doit être pris en charge. Sinon, appeler tika effacera votre flux d'entrée. Cependant, si vous utilisez la bibliothèque Apache IO pour contourner ce problème et que vous ne faites que transformer InputStream en fichier en mémoire.
import org.Apache.tika.*;
Tike tika = new Tika();
InputStream in = null;
FileOutputStream out = null;
try{
out = new FileOutputStream(c:/tmp.tmp);
IOUtils.copy(in, out);
String mimeType = tika.detect(out);
}catch(Exception e){
System.err.println(e);
} finally {
if(null != in)
in.close();
if(null != out)
out.close();
}
Si vous utilisez un service de repos JAX-RS, vous pouvez l'obtenir auprès du MultipartBody.
@POST
@Path( "/<service_path>" )
@Consumes( "multipart/form-data" )
public Response importShapeFile( final MultipartBody body ) {
String filename = null;
String InputStream stream = null;
for ( Attachment attachment : body.getAllAttachments() )
{
ContentDisposition disposition = attachment.getContentDisposition();
if ( disposition != null && PARAM_NAME.equals( disposition.getParameter( "name" ) ) )
{
filename = disposition.getParameter( "filename" );
stream = attachment.getDataHandler().getInputStream();
break;
}
}
// Read extension from filename to get the file's type and
// read the stream accordingly.
}
Où PARAM_NAME est une chaîne représentant le nom du paramètre contenant le flux de fichiers.