简单的问题:对于用户上传到我的servlet的文件,如何在不保存文件的情况下获取InputStream
的MIME类型(或内容类型)?
答案 0 :(得分:10)
我为byte []编写了自己的内容类型检测器,因为上面的库不合适或者我没有访问它们。希望这有助于某人。
// 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;
}
magicmimes.properties文件示例(不确定这些签名是否正确,但它们适用于我的用途)
# 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
答案 1 :(得分:7)
根据Real Gagnon's excellent site,针对您的案例的更好解决方案是使用Apache Tika。
答案 2 :(得分:6)
这取决于您从哪里获取输入流。如果从servlet获取它,则可以通过作为doPost参数的HttpServerRequest对象访问它。如果你正在使用像Jersey这样的某种休息API,那么可以使用@Context注入请求。如果您通过套接字上传文件,则您有责任将MIME类型指定为协议的一部分,因为您不会继承http标头。
答案 3 :(得分:1)
您可以查看Content-Type
header field并查看所使用的extension of the filename。对于其他一切,您必须运行更复杂的例程,例如通过Tika
等进行检查。
答案 4 :(得分:1)
只要不在其他地方使用slf4j日志记录,就可以将tika-app-1.x.jar添加到类路径中,因为它会导致冲突。如果使用tika检测输入流,则必须标记支持。否则,调用tika将清除输入流。但是,如果您使用apache IO库来解决此问题,只需将InputStream转换为内存中的文件。
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();
}
答案 5 :(得分:0)
如果使用JAX-RS休息服务,您可以从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.
}
PARAM_NAME是表示保存文件流的参数名称的字符串。
答案 6 :(得分:0)
我强烈支持“先自己动手,然后寻找图书馆解决方案”。幸运的是,这种情况就是这样。
您必须知道文件的“魔术号码”,即其签名。
让我举一个例子来检测InputStream
是否代表PNG文件。
PNG签名是通过在十六进制中附加以下内容组成的:
1)错误检查字节
2)字符串“ PNG”,如ASCII:
P - 0x50
N - 0x4E
G - 0x47
3)CR
(回车)-0x0D
4)LF
(换行符)-0xA
5)SUB
(代替)-0x1A
6)LF
(换行符)-0xA
所以,魔数是
89 50 4E 47 0D 0A 1A 0A
137 80 78 71 13 10 26 10 (decimal)
-119 80 78 71 13 10 26 10 (in Java)
137 -> -119
转换的说明 N位号可用于表示2^N
个不同的值。
对于8
或2^8=256
范围的字节(0..255
位)。
Java 考虑要签名的字节基元,因此范围为-128..127
。
因此,137
被认为是单字母代表-119 = 137 - 256
。
private fun InputStream.isPng(): Boolean {
val magicNumbers = intArrayOf(-119, 80, 78, 71, 13, 10, 26, 10)
val signatureBytes = ByteArray(magicNumbers.size)
read(signatureBytes, 0, signatureBytes.size)
return signatureBytes.map { it.toInt() }.toIntArray().contentEquals(magicNumbers)
}
当然,为了支持许多MIME类型,您必须以某种方式扩展此解决方案,如果对结果不满意,请考虑使用一些库。
答案 7 :(得分:-4)
我认为这解决了问题:
public String readIt(InputStream is) {
if (is != null) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is, "utf-8"), 8);
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
sb.append(line).append("\n");
}
is.close();
return sb.toString();
}
return "error: ";
}
它返回什么?例如对于png:&#34;♦PNG \ n \ n♦♦♦.....&#34;,对于xml:
非常有用,你不能尝试string.contains()来检查它是什么