views:

373

answers:

8

I need to detect whether the file I am attaching to an email is exceeding the server limit. I am not allowed to increase the JVM heap size to do this since it is going to affect the application performance.

If I don’t increase the JVM heap size, I will run into OutOfMemoryError directly.

I would like to know how do allocate the memory from OS instead of increasing the JVM’s heap size?

Thanks a lot!

A: 

You could allocate the memory natively via native code and JNI. However that sounds a painful way to do this.

Instead can't you give the JVM suitable memory configurations (via -Xmx) ? If the document you're mailing is so big that you can't easily handle it, then I'm not sure email is the correct medium to transfer it, and you should instead host it and send a link to it, or perhaps FTP it.

Brian Agnew
thanks for your quick responses on this.I wanted to change the Xmx setting from 256m to 512m but this solution got pushed back.I am dealing with two typical use cases:-- Trying to detect whether the attachment has exceeded the server policy before sending an email with large attachment to the server.-- Trying to detect an individual file's size before uploading it to the server.The problem right now is that server team does not have an API that tells me what is the server policy on size limitation...so I have to try to upload the file first which is not efficient...
JavaDoe
+3  A: 

Are you really trying to read the entire file to determine its size to check if it is less than some configured value (your question is not too easy to understand)? If so, why are you not using File#length() instead?

jarnbjo
I can read the file size before uploading the file to the server. However, the server team does not have an API in place to tell me what is the server policy in terms of what is the max file limit. I have to stream the file to the server and have it determine whether the file has exceeded the limit. This is not efficient. Since I can't increase the JVM heap size, how could I allocate the operating system memory to do this?Thanks a lot.
JavaDoe
Are you talking about the heap size of the client or of the server? Where do you need more memory and for what exact reason?
jarnbjo
I am talking about the heap size of the client.I need to read in this large file on the client side. I need to stream this file to the server after that. The server will be able to determine whether the file has exceeded the file size limit based on its policy.The server team does not have an API that tells me what is the file size policy.I need to allocate more memory on the client side in order to read this large file. I need to allocate more memory in the OS to do so. I would like to know what java API I can use to do this. Thanks.
JavaDoe
Why do you need to read the entire file from client-code to stream it to the server?
jarnbjo
I have to pass the file to the server so the server can tell me whether the file type is valid or the file has exceeded the size limit. The server team does not have an API that I can access for these policy information before I stream the file to the server.
JavaDoe
Yes, you just wrote that in your last comment. I asked why you have to keep the entire file in client memory to be able to do that.
jarnbjo
If I don't keep the entire file in client memory, could you advise me what else can I do to find out whether it has exceeded the server policy?
JavaDoe
Content getContent(String fileName) { Content myContent = new Content(); try { File file = new File(fileName); String fname; fname = file.getName(); myContent.setFileName(fname); FileInputStream fis = new FileInputStream(file); myContent.setInputStream(fis); } catch (FileNotFoundException e) { ............. } return myContent; }After this, the MimeMultipart will write the content to the outputstream.The information will be posted to the server.
JavaDoe
Once again, JavaDoe: How am I supposed to know what your Content class does? It is not part of the Java Mail, J2SE or other J2EE APIs. The "normal" way to create a mail message with a file attachment would be to use a MimeMultipart instance, which is fed by a FileDataSource.
jarnbjo
A: 

If you write your own stream handling code, you could create your own counter to track the number of bytes transmitted. I'd be surprised if there wasn't already some sort of Filter class that does this for you. Sun has a page about this. Search for 'CountReader'.

Kelly French
+3  A: 

If you need to stream the file to the server in order to find out whether it's too big, you still don't need to read the whole file into memory.

Instead, read maybe 10-100k into memory. Fill the buffer, send it to the server. Repeat until the file is done or the server complains. Then you don't need enough memory for the whole file.

jprete
hello, I just showed my code above. I am using FileInputStream to read the file into the memory....could you show me some pseudo code in terms of using a buffer to read 10-100K into memory? Our JVM heap size is 256MB. thanks a lot.
JavaDoe
As a starting point you could look at `FileInputStream.read(byte[] buffer)`; it will take a buffer (which you should make an appropriate size) and read into it until it runs out of buffer or runs out of file. Remember to keep the size that it returns - there's no guarantee of how much it will read at once - and write that much from the buffer to the outgoing stream. Repeat until `read()` returns -1, meaning that there's nothing left in the file. Someone else may know of any other input or output streams you need to interpose to make this work better in the real world.
jprete
A: 

If all the other solutions turn out to be unusable (and I would encourage you to find a better way than requiring the entire file to fit in memory!) you could consider using a direct ByteBuffer. It has the option of using mmap() or other system calls to map a file into your memory without actually reading / allocating space in the heap. You can do this by calling map() on a FileChannel -- API documentation. Note that this is potentially expensive and/or not supported on some platforms, so it should be considered suboptimal compared to any solution which does not require the entire file to be in memory.

Steven Schlansker
A: 
Socket s = /* go get your socket to the server */
InputStream is = new FileInputStream("foo.txt");
OutputStream os = s.getOutputStream();
byte[] buf = new byte[4096];
for(int len=-1;(len=is.read(buf))!=-1;) os.write(buf,0,len);
os.close();
is.close();

Of course handle your Exceptions.

Xepoch
A: 

Thanks so much for all the responses.

JavaDoe
A: 

If you're not allowed to increase the heap size because of memory constaints, doing an "under the table" memory allocation would cause the same problems. It sounds like you're looking for a loophole in the rules. Like, "My doctor says to cut down on how much I eat at each meal, so I'm eating more between meals to make up for it."

The only way I know of to allocate memory without using the Java heap would be to write JNDI calls to malloc the memory with C. But then how would you use this memory? You'd have to write more JNDI calls to interact with it. I think you'd end up basically re-inventing Java.

If the goal here is to send a large file, just use buffered streams and read/write it one byte at a time. A buffered stream, as the name implies, will take care of buffering for you so you're not really hitting the hard drive one byte at a time. It will really read, I think the default is 8k at a time, and then pass these bytes to you as you ask for them. Likewise, on the write side it will save up a few kb and and send them all in chunks.

So all you should have to do is open a BufferedInputStream and a BufferedOutputStream. Then write a loop that reads one byte from the input stream and writes it to the output stream until you hit end-of-file.

Something like:

OutputStream os=... however you're getting your socket ...
BufferedInputStream bis=new BufferedInputStream(new FileInputStream(fileObject));
BufferedOutputStream bos=new BufferedOutputStream(os);
int b;
while ((b=bis.read())!=-1)
  bos.write(b);
bis.close();
bos.close();

No need to make life complicated for yourself by re-inventing buffering. while (

Jay