views:

535

answers:

3

I'm getting InputStream of attached file by web service. When the user attaches an empty file, the input stream is not empty, but contains the header of the file (taht can be image, video, zip and others). When I read inputStream.available() I get 11 - the size of the header. I believe that for every type of file there is different header size, so I can't rely on that. I can't also read the file by ImageIO.read, because the file is not have to be an image file. Is there any way to know if the data in the input stream is only an header?

+1  A: 

Those headers must be specified somewhere. That specification should tell you whether they're binary or text, and their structure. If the specification is even remotely sane, there must be a way to tell when you've reached the end of the headers. Ideally, the headers should also provide a direct way to tell whether the file is empty (such as its size).

Read from the input stream, parse the headers and decide from there (if you run out of headers to parse and there's more data, you have a non-empty file).

Michael Borgwardt
I can receive many file types, and I don't want to hold a table of all file types with their header length
Alon
You don't have to; you just need to parse the headers to see whether they contain information about the file size, or see where they end and whether there's any more data afterwards. You must have the code to parse the headers *somewhere* already, otherwise you cannot use the image data anyway.
Michael Borgwardt
I don't need to use the image data,I just need to copy the fileAnd I get many types of files, not only images - also zip, audio, video...
Alon
Well, you can't copy the file either without knowing how to separate it from the headers.
Michael Borgwardt
Wait a second... Are we talking about *HTTP headers* here???
Michael Borgwardt
I don't think so but i'm not sure...I get the InputStream from JAXB by DataHandler.getInputStream()and this inputstream has the header
Alon
I suspect that you're approaching this the wrong way. If you're getting XML data, it's the job of an XML parser to give you the file data separate from the headers. JAXB is probably the wrong kind of XML parser to use though, since it requires the entire XML document to be read into memory. A SAX or StAX parser would be much better.
Michael Borgwardt
I found out that the size of the content I read from the input stream when no file is attached has the same size of the id of the file element given in SoapUI (Please see my comment to the first answer)
Alon
+1  A: 

The "for dummies" solution would be to read the InputStream until you hit either non-headers or the end of file. You can reset it if you want to read it "for real".

A smarter alternative would be to check your HTTPServletRequest.getContentLength() before even grabbing the InputStream. But that assumes the length is enough to tell empty headers from significant content.

Carl Smotricz
Thats the problem, I don't know what is the size of the header.The file can be from many types: image, zip, audio, video, etc.
Alon
There are 2 parts to my answer. You're ruling out the second part. That leaves suggestion 1.
Carl Smotricz
I have access to the attachment by JAXB DataHandler component.I don't have access to the HTTPServletRequestAnd even though, more than 1 file can be attached, some of them can be empty and some of them not
Alon
+1  A: 

Another practical solution: read and buffer the stream inside your application. Then check the buffer. If it's invalid, leave it for gc, otherwise, create a ByteArrayInputStream with that buffer and hand this (new) stream over to the correct file handler. It will not kill performance.

Quick draft:

public void handleIncomingStream(InputStream in) throws Exception /* KISS */{

    byte[] buffer = getBytes(in);

    if (containsJustHeader(buffer)) {
       return;
    }

    InputStream internal = new ByteArrayInputStream(buffer);
    StreamHandler handler = determineAppropriateStreamHandler(buffer); 
    handler.process(internal);
    internal.close();
}

Note that I invented the StreamHandler interface... With this example you'd implement stream handlers for the various filetypes, like image, text and so on. Note as well, that the exception handling in this example is the worst case, that I choose only to keep the example simple (KISS)

Edit

Quick draft without handler

public void handleIncomingStream(InputStream in) throws Exception /* KISS */{

    byte[] buffer = getBytes(in);

    if (containsJustHeader(buffer)) {
       throw new UnexpectedEmptyFileException(createErrorMessage(buffer));
    }

    InputStream internal = new ByteArrayInputStream(buffer);
    copyFile(internal);
    internal.close();
}

private boolean containsJustHeader(buffer) {
   return buffer.length < MAGIC_PLAIN_HEADER_SIZE; // 11 bytes?
}
Andreas_D
I just want to copy the file,I don't want to handle it in any way.I can get many file types (audio, zip, image, video, etc)and I don't want to handle each file type.I just want to determine if the file contains header only. If so - throw error message, If is full - copy it.Is my only option is to check that the length of the input stream is bigger than the header that supposed to be for each specific file type?
Alon
+1 for effort and patience.
Carl Smotricz