i have a servlet that copies a pdf file to the client using response output stream
private boolean copyStreamToStream(InputStream in, OutputStream target) {
logger.info("start copy file to stream");
try {
byte[] buffer = new byte[1024 * 8];
int len = in.read(buffer);
while (len != -1) {
target.write(buffer, 0, len);
len = in.read(buffer);
}
in.close();
target.flush();
target.close();
logger.info("end copy file to stream");
} catch (Exception ex) {
logger.error("Error: ", ex);
return false;
}
return true;
}
the InputStream for the pdf file on disk and OutputStream for response.getOutputStream()
the problem is that the PDF file is a big file and it takes a very long time to load it on client is there is any way to speed it up???
Send the file for download instead of passing it back as direct response object.
// Set the headers.
response.setContentType("application/x-download");
response.setHeader("Content-Disposition", "attachment; filename=" + filename);
// Send the file for download.
OutputStream out = response.getOutputStream( );
Edited.
Related
I'm trying to dynamically zip my files as a response for the user, but for some reason they become slightly corrupted on the way. The client can receive them, open the zip folder and browse the files. However, opening or extracting them won't work.
Here's my code:
private void dynamicallyZipFiles(IHTTPSession session) {
try {
// Let's send the headers first
OutputStream os = session.getOutputStream();
PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(os, "UTF-8")), false);
pw.append("HTTP/1.1 200 \r\n");
printHeader(pw, "Connection", "keep-alive");
printHeader(pw, "Content-Type", "application/zip, application/octet-stream");
printHeader(pw, "Content-Disposition", "attachment; filename=\"pack.zip\"");
printHeader(pw, "Transfer-Encoding", "chunked");
pw.append("\r\n");
pw.flush();
// Send all the files from the list of files
ChunkedOutputStream cos = new ChunkedOutputStream(os);
ZipOutputStream zos = new ZipOutputStream(cos);
final LinkedList<String> files = new LinkedList<String>();
files.add("file1.txt");
files.add("file2.txt");
while (!files.isEmpty()) {
String file = files.remove();
File toBeSent = new File(file);
try {
ZipEntry ze = new ZipEntry(file);
zos.putNextEntry(ze);
InputStream is = (InputStream) new FileInputStream(toBeSent);
long BUFFER_SIZE = 16 * 1024;
byte[] buff = new byte[(int) BUFFER_SIZE];
int len;
while ((len = is.read(buff)) > 0) {
zos.write(buff, 0, len);
}
is.close();
zos.flush();
cos.flush();
zos.closeEntry();
} catch (Exception e) {
e.printStackTrace();
}
}
// Files have been sent, send the closing chunk
//cos.write("0\r\n\r\n".getBytes(), 0, "0\r\n\r\n".getBytes().length);
// The above line of code was the problem! Without it, it works!
cos.flush();
zos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
// Helper for printing headers
private void printHeader(PrintWriter pw, String key, String value) {
pw.append(key).append(": ").append(value).append("\r\n");
}
I've been struggling for quite some hours already with this. I believe it has to have something to do with the closing chunk or with the closing of the connection?
I'm not sure what's the right order or way to close streams. I believe that when you have kind of "layered" streams and you close the top most one it will automatically close all the ones below too? And how about flush, if you flush a stream, will it flush the streams below it as well?With this I mean that my ZipStream for example, if I close it, will it close all the other streams as well? And if I flush it, will it flush all the other streams as well again?
Problem: My File not Launching which is requested from sever.
Okay I have written a server/client application but the problem is when i request for a file from the server it transfer over to the client but what I have notice is that I need to manually refresh the directory to get the file to be in the path or directory. So by saying that, I feel that this is why my code when request the file it doesn't launch.
My approach launching the file from the client after it had just been requested.
Here is my code below:
public static void receiveFile(String fileName) {
try {
int bytesRead;
InputStream in = sock.getInputStream();
DataInputStream clientData = new DataInputStream(in);
fileName = clientData.readUTF();
OutputStream output = new FileOutputStream((fileName));//need to state a repository
long size = clientData.readLong();
byte[] buffer = new byte[1024];
while (size > 0 && (bytesRead = clientData.read(buffer, 0, (int) Math.min(buffer.length, size))) != -1) {
output.write(buffer, 0, bytesRead);
size -= bytesRead;
}
output.close();
in.close();
File file = new File(fileName);
Desktop.getDesktop().open(file);
//System.out.println("File "+fileName+" received from Server.");
} catch (IOException ex) {
//Logger.getLogger(CLIENTConnection.class.getName()).log(Level.SEVERE, null, ex);
ex.printStackTrace();
}
}
Please can you look are tell me what you think I am doing wrong?
Server code:
Try flush the stream before close.
output.flush();
output.close();
I solve it my self the answer is to use the code below:
replace: Desktop.getDesktop().open(file);
with: Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler " + file);
I'm putting together some code to download files from an HTTP address in Android. I'd like to support download resumption if the download fails mid way.
The output I get when starting the download, then killing the wifi connection and restarting again several times is the following:
Start size 0
Stop size 12333416
Start size 12333416
Stop size 16058200
Start size 3724784
I cannot understand why after the first resumption, subsequent file size readings of the partially downloaded file do not match.
Thanks in advance!
public void download(String source, String target) throws IOException {
BufferedOutputStream outputStream = null;
InputStream inputStream = null;
try {
File targetFile = new File(target);
currentBytes = targetFile.length();
Log.i(TAG, "Start size " + String.valueOf(currentBytes));
outputStream = new BufferedOutputStream(new FileOutputStream(targetFile));
// create the input stream
URLConnection connection = (new URL(source)).openConnection();
connection.setConnectTimeout(mCoTimeout);
connection.setReadTimeout(mSoTimeout);
inputStream = connection.getInputStream();
inputStream.skip(currentBytes);
// calculate the total bytes
totalBytes = connection.getContentLength();
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) > 0) {
// write the bytes to file
outputStream.write(buffer, 0, bytesRead);
outputStream.flush();
currentBytes += bytesRead;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (outputStream != null) {
// close the output stream
outputStream.flush();
outputStream.close();
}
if (inputStream != null) {
// close the input stream
inputStream.close();
}
Log.i(TAG, "Stop size " + String.valueOf(currentBytes));
}
}
There are two things you are doing wrong:
To resume download to file you should append, not rewrite the file. Use special constructor for output stream:
FileOutputStream(targetFile, true)
To request part of file from server you should use HTTP 1.1 property "Range". You can do it like this:
HttpURLConnection httpConnection = (HttpURLConnection) connection;
connection.setRequestProperty("Range", "bytes=" + currentBytes + "-");
I need to read a file (that is not available on web) on the server and output it to the user as a downloadable file.
The scenario is
The user click a link from an XPage
The request is sent to the server which reads a predefined file in the server file system
The file is brought back to the user as a downloadable file in the webbrowser.
The file on the server can be in any format, e.g .pdf, .exe, .doc etc
It does not matter if this is done on SSJS or in java.
I would really appreicate some code
Here is a similar question:
How to stream file from xPages?
And here is part of the Java code taken from there and completed by me (+a fix from you!). I have now tested it also and it works:
FacesContext facesContext = FacesContext.getCurrentInstance();
XspHttpServletResponse response = (XspHttpServletResponse) facesContext.getExternalContext().getResponse();
String strFileName = "myfile.txt";
String strFilePath= "c:" + File.separator + strFileName;
response.setContentType(URLConnection.guessContentTypeFromName(strFileName));
response.setHeader("Content-Disposition","attachment;filename=" + strFileName);
//File file = new File(strFilePath);
FileInputStream fileIn = new FileInputStream(strFilePath);
ServletOutputStream out = response.getOutputStream();
int iLen = 0;
byte[] btBuffer = new byte[10240]; // Not sure about optimal buffer size
while ((iLen = fileIn.read(btBuffer)) != -1) {
out.write(btBuffer, 0, iLen);
}
facesContext.responseComplete();
out.close();
You could do all this in SSJS also.
If guessContentTypeFromName does not guess it then you need to modify the definition file on server. Or if you have a limited set of file types you can place the MIME-type table in your code/application.
Here is the code I came up with to do this, def not production code.
public static byte[] grabFile(String readFile) throws IOException {
File file = new File(readFile);
ByteArrayOutputStream ous = new ByteArrayOutputStream();
InputStream ios = new FileInputStream(file);
try {
byte []buffer = new byte[4096];
int read = 0;
while ( (read = ios.read(buffer)) != -1 ) {
ous.write(buffer, 0, read);
}
} finally {
try {
if ( ous != null )
ous.close();
} catch ( IOException e) {
}
try {
if ( ios != null )
ios.close();
} catch ( IOException e) {
}
}
return ous.toByteArray();
}
public static void download() throws IOException {
byte[] data = grabFile("\\\\server\\path\\to\\file.pdf");
HttpServletResponse response = (HttpServletResponse)FacesContext.getCurrentInstance().getExternalContext().getResponse();
response.reset();
response.setContentType("application/pdf");
response.setHeader("Content-disposition", "attachment; filename=\"filename.pdf\"");
OutputStream output = response.getOutputStream();
output.write(data);
output.close();
FacesContext.getCurrentInstance().responseComplete();
}
Then just call the download method from the beforeRenderResponse of your Xpage
I am using following code for reading image file from socket. It reads all the bytes from server because size of file on server and android machine are same. When i open this file it does not open the file and generate error that is the file is corrupted or too large.
public Bitmap fileReceived(InputStream is)
throws FileNotFoundException, IOException {
Bitmap bitmap = null;
String baseDir = Environment.getExternalStorageDirectory().getAbsolutePath();
String fileName = "a.png";
String imageInSD = baseDir + File.separator + fileName;
System.out.println(imageInSD);
if (is!= null) {
FileOutputStream fos = null;
BufferedOutputStream bos = null;
try {
fos = new FileOutputStream(imageInSD);
bos = new BufferedOutputStream(fos);
byte[] aByte = new byte[1024];
int bytesRead;
while ( true ) {
bytesRead = is.read(aByte);
bos.write(aByte, 0, bytesRead);
if ( is.available()==0)
break;
}
bos.flush();
bos.close();
// is.reset();
// here it give error i.e --- SkImageDecoder::Factory returned null
bitmap = BitmapFactory.decodeFile(imageInSD);
} catch (IOException ex) {
// Do exception handling
Log.i("IMSERVICE", "exception ");
}
}
return bitmap;
}
Don't use available() for this, it won't work reliably!
The docs state:
[ available() ] Returns an estimate of the number of bytes that can be read [...] It is never correct to use the return value of this method to allocate a buffer intended to hold all data in this stream.
Do it like:
while ( (bytesRead = is.read(aByte)) > 0 ) {
bos.write(aByte, 0, bytesRead);
}