How to set encoding to file for download - java

I have a method which start download of text file that is stored in oracle.
The column type is BLOB. I'm using this code below to init download, but I have no idea how set encode to this file when client downloaded it.
if (result.next()) {
String fileName0 = String.valueOf(result.getDate(columnData));
String fileName1 = String.valueOf(result.getInt(columnNumSolit));
String fileName2 = String.valueOf(result.getInt(columnNumComplto));
BLOB blob = ((OracleResultSet) result).getBLOB(columnFile);
InputStream inputStream = blob.getBinaryStream();
//int fileLength = inputStream.available();
int fileLength = blob.getChunkSize();
ServletContext context = getServlet().getServletContext();
// Set MIME to file.
String mimeType = context.getMimeType(fileName0+fileName1+fileName2+ext);
if (mimeType == null) {
mimeType = "application/octet-stream";
}
// header to response.
response.setContentType(mimeType);
response.setContentLength(fileLength);
String headerKey = "Content-Disposition";
String headerValue = String.format("attachment; filename=\"%s\"",fileName0+fileName1+fileName2+ext);
response.setHeader(headerKey, headerValue);
// write file to client.
OutputStream outStream = response.getOutputStream();
byte[] buffer = new byte[fileLength];
int bytesRead = -1;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outStream.write(buffer, 0, bytesRead);
}
inputStream.close();
outStream.close();
tipoSolit = null;
}else {
//do something
}

What behavior are you trying to get the browser to do? Are you sending a video or mp3 or what? The mimetype is set by the headers you send before the file. If know of a website that has the behavior you are looking for, you can simply view what headers they send in chrome or in wireshark and then just use those in your own code.
One of the problems with file-type encoding is that you need to keep the encoding correct for each step that the bytes take. This means that if any step in the "upload->storage in db->fetching db->download" removes utf-8 encoding, you get the wrong answer. I wrote a post about my travels with UTF-8 and MySQL here: https://stackoverflow.com/a/14411280/836450 I would suggest sending a file that has a single utf-8 character, and then debugging the entire chain by hand.

Related

File download from the browser via DB has extra bytes added causing corruption messages from microsoft applications

<%
Document downloadFile = null;
String mimeType = null;
try{
downloadFile = new DocumentsDao().loadById(Long.parseLong(request.getParameter("id")));
// gets MIME type of the file
mimeType = downloadFile.getFileType();
if (mimeType == null) {
// set to binary type if MIME mapping not found
mimeType = "application/octet-stream";
}
System.out.println("MIME type: " + mimeType);
}catch (Exception e){
return;
}
// modifies response
response.reset();
response.resetBuffer();
response.setContentType(mimeType);
response.setContentLength((int) downloadFile.getDocumentData().length);
// forces download
String headerKey = "Content-Disposition";
String headerValue = String.format("attachment; filename=\"%s\"", downloadFile.getFileName());
response.setHeader(headerKey, headerValue);
// obtains response's output stream
OutputStream outStream = response.getOutputStream();
byte[] buffer = new byte[8192];
int bytesRead = -1;
System.out.println("### Length from db = "+downloadFile.getDocumentData().length);
ByteArrayInputStream inStream = new ByteArrayInputStream(downloadFile.getDocumentData());
while ((bytesRead = inStream.read(buffer)) != -1) {
outStream.write(buffer, 0, bytesRead);
}
inStream.close();
outStream.close();
response.flushBuffer();
return;
%>
The above code in a JSP produces a file to download which has an additional sequence of 0d0a x 4 at the end which causes the microsoft applications word and excel to complain and have to repair the file which has been downloaded.
I thought it might be the upload of the file but it was not, and retrieving from the database is fine. So the input stream is fine the problem occurs after the output stream is closed.
Errors you get are 'Word found unreadable content' 'Excel found unreadable content'
Has anyone seen this?
cheers
Charlie
The conversion of the JSP to servlet introduced the 0d0a X 4 characters. I used fiddle to find that the Apache Tomcat web server was altering the content length and sending the bytes. I looked at working apps at work and they all used servlets to do the job so I converted the above code to a servlet and it worked perfectly.
So don't use JSPs for this purpose.

My base64 encoded byte[] stream has extra characters after sent through a http response

I encode a pdf into a base64 byte[] stream and I want to send it as a http response to the browser. The problem is that the browser fails to load pdf.
I compared the base 64 string which I printed into the IDE console and the one from the browser console. The one from the IDE console is correct and the one from the browser has extra characters.
So, my base64 byte[]stream gets broken somehow when it's sent as a http response ? How do I solve this?
L.e. : The code
FileInputStream inputFileInputStream = null;
ServletOutputStream outputFileOutputStream = null;
File exportFile = new File(exportedReport);
int fileSize = (int) exportFile.length();
String fullPathToExport = exportFile.getAbsolutePath();
File fullPathFile = new File(fullPathToExport);
try {
// test to see if the path of the file is correct
System.out.println("The file is located at: "
+ exportFile.getAbsolutePath());
response.reset();
response.setContentType("application/pdf");
response.setContentLength(fileSize);
response.addHeader("Content-Transfer-Encoding", "base64");
response.setHeader( "Content-Disposition", "inline; filename=\"" + exportedReport +"\"");
inputFileInputStream = new FileInputStream(fullPathFile);
outputFileOutputStream = response.getOutputStream();
if (bytesToRead == -1) {
bytesToRead = (int)fullPathFile.length();
}
byte[] buffer = new byte[bytesToRead];
int bytesRead = -1;
while((inputFileInputStream != null) && ((bytesRead = inputFileInputStream.read(buffer)) != -1)){
if (codec.equals("base64")) {
//outputFileOutputStream.write(Base64.encodeBytes(buffer).getBytes("UTF-8"), 0, bytesToRead);
outputFileOutputStream.write(org.apache.commons.codec.binary.Base64.encodeBase64(buffer));
} else {
outputFileOutputStream.write(buffer, 0, bytesToRead);
}
}
inputFileInputStream.close();
outputFileOutputStream.flush();
outputFileOutputStream.close();
Your code has one major problem:
You are not sending one base64 encoded data part but many base64 encoded data parts (concatenated). But two or more base64 encoded data parts are not equal to one base64 encoded data part.
Example:
base64("This is a test") -> "VGhpcyBpcyBhIHRlc3Q="
base64("This ")+base64("is a ")+base64("test") -> "VGhpcyA=aXMgYSA=dGVzdA=="
You should use the org.apache.commons.codec.binary.Base64InputStream instead of the Base64.encodeBase64() utility method. Read the whole FileInputStream through it and you will get a valid base64 encoded data stream.
Anyway what you are doing is not necessary. You can transfer any 8 bit data via HTTP without further encoding.

Create a text file for download on the fly with Java

I have a Java Servlet that generates randomly thousands of Strings every time is called. I want the user to be able to get them in a file when he calls the Servlet. I don't want to write first the file on disk or memory.
Is there a way to write the file on the fly when the user calls the servlet?
Thanks
Any text that you generate in the Servlet can simply be written to the OutputStream returned by ServletResponse.getOutputStream().
If you want the output to be downloadable as a file, you can follow the approach in this answer - https://stackoverflow.com/a/11772700/1372207
The difference would be, that the Content-type would be text/plain and instead of reading from another inputstream, you would just write the String objects directly to the ServletOutputStream using the print(String) method.
If you use the idea to write content to HttpServletResponse's output stream while offering download service, rather than saving the content locally and then reading the file as FileInputStream, you can just convert the file content to InputStream by InputStream stream = new ByteArrayInputStream(exampleString.getBytes("UTF-8"));.
The following code partially references https://www.codejava.net/java-ee/servlet/java-servlet-download-file-example.
public void doDownload(HttpServletRequest request, HttpServletResponse response) throws IOException {
String fileName = "xxx.txt";
String fileContent = "";
// get absolute path of the application
ServletContext context = request.getServletContext();
// get MIME type of the file
String mimeType = context.getMimeType(fileName);
if (mimeType == null) {
// set to binary type if MIME mapping not found
mimeType = "application/octet-stream";
}
setResponseHeader(response, fileName, mimeType, (int) fileContent.length());
InputStream inputStream = new ByteArrayInputStream(fileContent.getBytes("UTF-8"));
// get output stream of the response
OutputStream outStream = response.getOutputStream();
byte[] buffer = new byte[4096];
int bytesRead = -1;
// write bytes read from the input stream into the output stream
while ((bytesRead = inputStream.read(buffer)) != -1) {
outStream.write(buffer, 0, bytesRead);
}
inputStream.close();
outStream.close();
}
private void setResponseHeader(HttpServletResponse response, String fileName, String mimeType, Integer fileLength) {
response.setContentType(mimeType);
response.setContentLength(fileLength);
response.setContentType("application/octet-stream; charset=UTF-8");
String headerKey = "Content-Disposition";
String headerValue = String.format("attachment; filename=\"%s\"", fileName);
response.setHeader(headerKey, headerValue);
response.addHeader("Pargam", "no-cache");
response.addHeader("Cache-Control", "no-cache");
}

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.

Download process is not visible while servlet is downloading pdf

I m using content-disposition to download pdf . When I click the download button, the complete pdf file is downloaded first and then browser shows the dialog box to save the file. I want the browser to show the process of downloading. The following is my servlet code:
String filename = "abc.pdf";
String filepath = "/pdf/" + filename;
resp.setContentType("application/pdf");
resp.addHeader("content-disposition", "attachment; filename=" + filename);
ServletContext ctx = getServletContext();
InputStream is = ctx.getResourceAsStream(filepath);
System.out.println(is.toString());
int read = 0;
byte[] bytes = new byte[1024];
OutputStream os = resp.getOutputStream();
while ((read = is.read(bytes)) != -1) {
os.write(bytes, 0, read);
}
System.out.println(read);
os.flush();
os.close();
}catch(Exception ex){
logger.error("Exception occurred while downloading pdf -- "+ex.getMessage());
System.out.println(ex.getStackTrace());
}
The progress cannot be determined without knowing the response body's content length beforehand in the client side. To let the client know about the content length, you need to set the Content-Length header in the server side.
Change the line
InputStream is = ctx.getResourceAsStream(filepath);
to
URL resource = ctx.getResource(filepath);
URLConnection connection = resource.openConnection();
response.setContentLength(connection.getContentLength()); // <---
InputStream is = connection.getInputStream();
// ...
Unrelated to the concrete problem, your exception handling is bad. Replace the line
System.out.println(ex.getStackTrace());
by
throw new ServletException(ex);

Categories

Resources