Download servlet is very slow - java

I have written a servlet which will download the file from a server location. In our own INTRAnet the download seems to be very very slow and also when I have the Adobe addon installed in my browser and if I am downloading a PDF file, the Adobe addon will display the progress bar while downloading the PDF but this is not happening in my case! Below is my code! Should I not response it as attachment?
PrintWriter out = response.getWriter();
response.setContentType("APPLICATION/OCTET-STREAM");
response.setIntHeader("Refresh", 1);
response.setHeader("Content-Disposition",
"inline; filename=\"" + fileNameWithExtension
+ "\"");
FileInputStream fileInStream = new FileInputStream(
filePathWithExtension);
BufferedInputStream bufferInStream = new BufferedInputStream(
fileInStream);
int cnt;
while ((cnt = bufferInStream.read()) != -1) {
out.write(cnt);
}
fileInStream.close();
out.close();
Not sure if there is a better way to do. Basically I tried converting one of my dot net code into this Java Servlet. THe current .NET code is very fast compared to this!
This is hosted on Apache Tomcat and the .NET code is hosted on IIS.

Reading and writing a byte at a time is horrifically inefficient. The canonical way to copy a stream in Java is as follows:
byte[] buffer = new byte[8192]; // or more if you like
int count;
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
And you should not use a Writer here, use an OutputStream.

Related

Java: Binary File Upload using Restlet + Apache Commons FileUpload

I have a REST API with Restlet 2.3 and need to implement a file-uploading functionality to it.
The problem is that, when someone uploads a file using a POST (with a multipart/form-data Content-Type), the file reaches the server with another encoding.
To test this, I printed the contents of the original file in a Unix Terminal and then printed it again before parsing the requet with Apache Commons FileUpload (with almost the same code of this example http://restlet.com/technical-resources/restlet-framework/guide/2.2/extensions/fileupload). Both printed contents are very similar, but the original file has less characters, so i assume that my Java server is using the wrong encoding to interpret the file.
The file I sent is a PNG image. With text files the server works perfectly, but when I send photos or any binary file, the problem appears.
I don't know how you exactly did to check the received content. First you should check the content type that is used for your file part within the content of your multipart request. You should have something like that for a JPG image:
-----------------------------75956101888331271337088331
Content-Disposition: form-data; name="fileToUpload"; filename="myimage.jpg"
Content-Type: image/jpeg
Secondly, I don't know how you actually write the content you received. Apache Commons IO brings an utility method IOUtils.copy that provides a simple solution to write in an OutputStream the content received from an InputStream. See how ti can be used in your context:
while (fileIterator.hasNext()) {
FileItemStream fi = fileIterator.next();
if (fi.getFieldName().equals("fileToUpload")) {
FileOutputStream fos = new FileOutputStream(
"output"+File.separator+fi.getFieldName());
IOUtils.copy(fi.openStream(), fos);
fos.close();
}
}
IMO, the encoding aspect only applies for text not for binary content.
Hope it helps,
Thierry
I actually solved it by using Google's ByteStreams class:
while (fileIterator.hasNext()) {
FileItemStream fi = fileIterator.next();
if (fi.getFieldName().equals(FILE_TO_UPLOAD)) {
byte[] byteArray = ByteStreams.toByteArray(fi.openStream());
result = new String(byteArray,Charset.forName("ISO-8859-1"));
}
}
I had the similar problem when uploading the image file. This is how I fixed. The problem was in my case the data read from the inputstream. As it is reading from a socket no guarantee that you will have the full buffer of your array filled. Therefore you should check your data size before writing it to the outputbuffer/file. Here is my code hope it helps. Also available in repository https://github.com/esabilbulbul/java-servlet-fileupload/blob/master/README.md
// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload();
upload.setHeaderEncoding("UTF-8");
// Parse the request
FileItemIterator iter = upload.getItemIterator(request);
while (iter.hasNext())
{
FileItemStream item = iter.next();
String name = item.getFieldName();
//InputStream attachmentStream = item.openStream();
//byte[] attachmentBytes = ByteStreams.toByteArray(attachmentStream);
//InputStream stream = item.getInputStream();
InputStream stream = item.openStream();
if (item.isFormField())
{
//System.out.println("Form field " + name + " with value " + Streams.asString(stream) + " detected.");
}
else
{
System.out.println("File field " + name + " with file name "+ item.getName() + " detected.");
// Process the input stream
FileOutputStream fout= new FileOutputStream ("c:\\" + item.getName());
BufferedOutputStream bout= new BufferedOutputStream (fout);
BufferedInputStream bin= new BufferedInputStream(stream);
byte buf[] = new byte[2048];
int len=0;
while ((len = bin.read(buf)) > 0)//((bin.read(buf)) != -1)
{
bout.write(buf, 0, len);
if (len<2048)
len = len;
}
bout.close();
bin.close();
}
}

Downloading files using servlets

hi i have tried the following java codes which works fine if i use them as a java application but when i use the same code in my servlet page they dont work means i am not able to download the files. Please suggest what changes should i do so that i can download the file using Servlets.
a.
java.io.BufferedInputStream in = new java.io.BufferedInputStream(new java.net.URL("http://169.254.174.150:8084/WebApplication1/files/check.txt").openStream());
File f1 = new File("D:\\a.txt");
java.io.FileOutputStream fos = new java.io.FileOutputStream(f1);
java.io.BufferedOutputStream bout = new BufferedOutputStream(fos, 1024);
byte data[] = new byte[1024];
while (in.read(data, 0, 1024) >= 0) {
bout.write(data);
}
bout.close();
in.close();
}
b. http://www.javabeat.net/examples/2012/04/13/download-file-from-http-https-server-using-java/
One of the older JavaBeat examples like the one you specified can be found here
I found other solutions too but this seems to be the most comprehensive.
Couple of things, insetad of writing it to a file try wrting the data directly to the responce. Before writing data you will have to set the following parameters to the responce
//byte[] filedata = ; intialize your file contents
String filename = "a.txt";
// set the header information in the response.
res.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\";");
res.setContentType("application/x-unknown");
ByteArrayInputStream byteStream = new ByteArrayInputStream(filedata);
BufferedInputStream bufStream = new BufferedInputStream(byteStream);
ServletOutputStream responseOutputStream = res.getOutputStream();
int data = bufStream.read();
while (data != -1)
{
responseOutputStream.write(data);
data = bufStream.read();
}
bufStream.close();
responseOutputStream.close();
where res is a HttpServletResponse object. After this you can write data to responseOutputStream.

Servlet - Force overwrite downloaded file

How to change this code to force overwrite existing previously opened file saved on drive? It's part of servlet for opening pdf files on client side.
response.reset();
response.setContentType("application/pdf");
response.setContentLength(file.length());
response.setHeader("Content-disposition", "inline; filename=\"" + file.getName() + "\"");
BufferedInputStream input = null;
BufferedOutputStream output = null;
try
{
input = new BufferedInputStream(new FileInputStream(file), DEFAULT_BUFFER_SIZE);
output = new BufferedOutputStream(response.getOutputStream(), DEFAULT_BUFFER_SIZE);
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
int length;
while ((length = input.read(buffer)) > 0)
{
output.write(buffer, 0, length);
}
}
finally
{
close(output);
close(input);
}
Each next copy of opened file has a new index, e.g. test.pdf, test(1).pdf and so on
You can't control that.
That is dependent on client's OS file system implementation
The best you can do it to configure the client browser to ask whether to overwrite or not, for example in Firefox it is:
To my knowledge asking to overwrite is the default behavior in Opera.
before going to write check whether the given file is exist or not?
using file api file.exists() if it exists, delete given file using file api file.delete() and continue with writing process

URL Connection (FTP) in Java - Simple Question

I have a simple question. I'm trying to upload a file to my ftp server in Java.
I have a file on my computer, and I want to make a copy of that file and upload it. I tried manually writing each byte of the file to the output stream, but that doesn't work for complicated files, like zip files or pdf files.
File file = some file on my computer;
String name = file.getName();
URL url = new URL("ftp://user:password#domain.com/" + name +";type=i");
URLConnection urlc = url.openConnection();
OutputStream os = urlc.getOutputStream();
//then what do I do?
Just for kicks, here is what I tried to do:
OutputStream os = urlc.getOutputStream();
BufferedReader br = new BufferedReader(new FileReader(file));
String line = br.readLine();
while(line != null && (!line.equals(""))) {
os.write(line.getBytes());
os.write("\n".getBytes());
line = br.readLine();
}
os.close();
For example, when I do this with a pdf and then try and open the pdf that I run with this program, it says an error occurred when trying to open the pdf. I'm guessing because I am writing a "\n" to the file? How do I copy the file without doing this?
Do not use any of the Reader or Writer classes when you're trying to copy the byte-for-byte exact contents of a binary file. Use these only for plain text! Instead, use the InputStream and OutputStream classes; they do not interpret the data at all, while the Reader and Writer classes interpret the data as characters. For example
OutputStream os = urlc.getOutputStream();
FileInputStreamReader fis = new FileInputStream(file);
byte[] buffer = new byte[1000];
int count = 0;
while((count = fis.read(buffer)) > 0) {
os.write(buffer, 0, count);
}
Whether your URLConnection usage is correct here, I don't know; using Apache Commons FTP (as suggested elsewhere) would be an excellent idea. Regardless, this would be the way to read the file.
Use a BufferedInputStream to read and BufferedOutputStream to write. Take a look at this post: http://www.ajaxapp.com/2009/02/21/a-simple-java-ftp-connection-file-download-and-upload/
InputStream is = new FileInputStream(localfilename);
BufferedInputStream bis = new BufferedInputStream(is);
OutputStream os =m_client.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(os);
byte[] buffer = new byte[1024];
int readCount;
while( (readCount = bis.read(buffer)) > 0) {
bos.write(buffer, 0, readCount);
}
bos.close();
FTP usually opens another connection for data transfer.
So I am not convinced that this approach with URLConnection is going
to work.
I highly recommend that you use specialized ftp client. Apache commons
may have one.
Check this out
http://commons.apache.org/net/api/org/apache/commons/net/ftp/FTPClient.html

Stream linearized PDF from servlet to browser (fast web view)

I'm running a web app that provides a servlet. this servlet opens a pdf file from a Network File System and finally streams it to the requesting browser.
All the pdf files are linearized by adobe lifecycle pdf generator and ready for fast web view.
unfortunately, the fast web view does not work. I guess it's a problem of how to open and stream the file in java code and the setting of response header info.
if i deploy a test pdf within my webapp onto the jboss AS and open it directly from the browser by url, the incrementel loading works.
can anyone help me?
Here's the code of my servlet:
response.setContentType("application/pdf");
response.setHeader("Expires", "0");
response.setHeader("Cache-Control",
"must-revalidate, post-check=0, pre-check=0");
response.setHeader("Content-Disposition",
"inline;filename=" + documentReference);
response.setHeader("Accept-Ranges", "bytes");
File nfsPDF = new File(NFS_DIRECTORY_PATH + documentReference);
FileInputStream fis = new FileInputStream(nfsPDF);
BufferedInputStream bis = new BufferedInputStream(fis);
ServletOutputStream sos = response.getOutputStream();
byte[] buffer = new byte[(int) nfsPDF.length()];
while (true) {
int bytesRead = bis.read(buffer, 0, buffer.length);
if (bytesRead < 0) {
break;
}
sos.write(buffer, 0, bytesRead);
}
sos.flush();
//... closing...
Let's see. You want to send a file in parts, right? Then you should check Range header (HTTP Header) and send only bytes in this range. I'm correct?
I'm not familiar with "PDF fast web view" feature, but in you're code your're first reading the file completely into buffer and then you write it out. The client won't receive anything before the call to sos.flush(). In fact your while loop is obsolete because there will always be just one run.
Maybe you should try to read/write the stuff blockwise.
byte[] buffer = new byte[1024];
while (true) {
int bytesRead = bis.read(buffer, 0, buffer.length);
if (bytesRead < 0) {
break;
}
sos.write(buffer, 0, bytesRead);
sos.flush();
}
sos.flush();

Categories

Resources